【参考视频】www.bilibili.com/video/BV1m8…
SpringBoot项目的创建和接口配置
做一个springboot项目,从创建项目到实现浏览器访问localhost:8080/hello返回字符串hello world的全流程
1. 创建项目
- idea
- 新建项目
- Spring initializr->配置选择语言:java类型:maven组:com.jwz包名:com.jwz打包:jar
- 选择web->spring web
- finish
创建完成项目后可以把.idea、.mvn、.gitignore、HELP.md、mvnw、mvnw.cmd等无关项目的文件和文件夹删除
2.配置接口
在项目的com.jwz下新建controller包再创建HelloController.java文件,放入以下内容
package com.jwz.sprdemo02.controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
// 请求处理类
@RestController
public class HelloController {
// 定义接口名
@RequestMapping("/hello")
public String hello(){
System.out.println("Hello World");
return "Hello World";
}
}
然后找到项目默认生成的Application.java的文件,右键运行即可
浏览器访问:http://localhost:8080/hello 即可显示Hello World
获取参数
原始方式
package com.jwz.sprdemo02.controller;
import jakarta.servlet.http.HttpServletRequest;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
// 请求处理类
@RestController
public class HelloController {
// 定义接口名
@RequestMapping("/hello")
public String hello(HttpServletRequest request){
// 浏览器访问:http://localhost:8080/hello?name=萧寂&age=18
// 获取get请求参数
String name = request.getParameter("name");
String age = request.getParameter("age");
int ageInt = Integer.parseInt(age);
System.out.println(name+ageInt);
return name+ageInt;
}
}
SpringBoot方式
package com.jwz.sprdemo02.controller;
import jakarta.servlet.http.HttpServletRequest;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
// 请求处理类
@RestController
public class HelloController {
// 定义接口名
@RequestMapping("/hello")
public String hello(@RequestParam("name") String name ,@RequestParam("age") Integer age){
System.out.println(name+":"+age);
return name+age;
}
}
// get请求:http://localhost:8080/hello?name=萧寂&age=18
// post请求:http://localhost:8080/hello 在body的x-www-form-urlencoded里面添加对应参数即可
// 上面获取参数方法可以获取get和post参数的,只是请求方法和参数的传递方式有点区别
参数对应不上的情况
// 下面这个方法,比如我请求地址和传参为:http://localhost:8080/hello?name=萧寂&age=18
// 可以发现,参数没有username 只有name,那么RequestParam这个注解就可以指定参数,当匹配到RequestParam指定的属性的值时也默认这个值为username的值,如果匹配不到RequestParam指定的参数,则会抛出400错误,如下所示,第二个参数改为false,代表此参数不是必填的,则不会报错,会将当前参数为null
public String hello(@RequestParam(value = "name",required = false) String username ,@RequestParam("age") Integer age){
// 此时匹配到name="萧寂" 也就相当于username="萧寂"
System.out.println(username+":"+age);
return username+age;
}
// @ReguestParam中的required属性默认为true,代表该请求参数必须传递,如果不传递将报错。如果该参数是可选的,可以将required属性设置为false。
参数接收
实体参数
package com.jwz.sprdemo02.user;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
public class simplePojo {
private String name;
private Integer age;
public simplePojo() {
}
public simplePojo(String name, Integer age) {
this.name = name;
this.age = age;
}
/**
* 获取
* @return name
*/
public String getName() {
return name;
}
/**
* 设置
* @param name
*/
public void setName(String name) {
this.name = name;
}
/**
* 获取
* @return age
*/
public Integer getAge() {
return age;
}
/**
* 设置
* @param age
*/
public void setAge(Integer age) {
this.age = age;
}
public String toString() {
return "simplePojo{name = " + name + ", age = " + age + "}";
}
}
@RestController
class ControllerSimplePojo{
// 实体参数
@RequestMapping("/simplePojo")
public String simplePojo(simplePojo simplePojo){
// 访问如下地址: http://localhost:8080/simplePojo?name=萧寂&age=18
System.out.println(simplePojo); // simplePojo{name = 萧寂, age = 18}
// 访问如下地址: http://localhost:8080/simplePojo?age=18
// 不传哪个哪个就为null
System.out.println(simplePojo); // simplePojo{name = null, age = 18}
return "OK";
}
}
数组集合参数
@RequestMapping("/arrayHobby")
public String arrayHobby(@RequestParam("hobby") String[] hobby){
// 请求方式get,地址为:http://localhost:8080/arrayHobby?hobby=篮球&hobby=跳绳&hobby=足球
System.out.println(Arrays.toString(hobby)); // [篮球, 跳绳, 足球]
return "OK";
}
// 使用集合接收
@RequestMapping("/listHobby")
public String listHobby(@RequestParam("hobby") List<String> hobby){
// 请求方式get,地址为:http://localhost:8080/listHobby?hobby=篮球&hobby=跳绳&hobby=足球
System.out.println(hobby); // [篮球, 跳绳, 足球]
return "OK";
}
日期参数
@RequestMapping("/dateParams")
public String dateParams(@RequestParam("updateTime") @DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss") LocalDateTime updateTime){
// 请求方式get,地址为:http://localhost:8080/dateParams?updateTime=2024-04-27 10:00:25
System.out.println(updateTime); // 2024-04-27T10:00:25
return "OK";
}
JSON参数
package com.jwz.sprdemo02.json;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
class Address {
private String province;
private String city;
public Address(String province, String city) {
this.province = province;
this.city = city;
}
public Address() {
}
public String getProvince() {
return province;
}
public void setProvince(String province) {
this.province = province;
}
public String getCity() {
return city;
}
public void setCity(String city) {
this.city = city;
}
@Override
public String toString() {
return "Address{" +
"province='" + province + '\'' +
", city='" + city + '\'' +
'}';
}
}
class User {
private String name;
private Integer age;
private Address address;
public User() {
}
public User(String name, Integer age, Address address) {
this.name = name;
this.age = age;
this.address = address;
}
/**
* 获取
* @return name
*/
public String getName() {
return name;
}
/**
* 设置
* @param name
*/
public void setName(String name) {
this.name = name;
}
/**
* 获取
* @return age
*/
public Integer getAge() {
return age;
}
/**
* 设置
* @param age
*/
public void setAge(Integer age) {
this.age = age;
}
/**
* 获取
* @return address
*/
public Address getAddress() {
return address;
}
/**
* 设置
* @param address
*/
public void setAddress(Address address) {
this.address = address;
}
public String toString() {
return "User{name = " + name + ", age = " + age + ", address = " + address + "}";
}
}
@RestController
class ControllerUser{
@RequestMapping("/jsonParams")
public String jsonParams(@RequestBody User jsonParams){ // 接收到的参数交给User去处理
// 请求方式post,地址为:http://localhost:8080/jsonParams 参数在apifox的body的json里面填写json数据{"name":"萧寂","age":16,"address":{"province":"北京","city":"北京"}}
// 这里有个小问题,json数据格式和raw的一样,如果在json填写数据后再点击raw然后去发请求,此时参数是raw里面的,我这里返回来了415错误,也就是说在json里面写完参数必须直接发请求,不要切换到其他栏,都会报错
System.out.println(jsonParams); // User{name = 萧寂, age = 16, address = Address{province='北京', city='北京'}}
return "OK";
}
}
路径参数
就是http ://localhost:8080/add/1/123 这个1和123就是路径上面携带的参数
@RequestMapping("/pathParams/{id}/{preId}")
public String pathParams(@PathVariable("id") Integer id,@PathVariable("preId") Integer preId){
// 请求方式get,地址为:http://localhost:8080/pathParams/1/1234
System.out.println(id+":"+preId); // 1:1234
return "OK";
}
封装统一的返回格式
{
code:0,
msg:"成功",
data:[...]
}
工具类
package com.jwz.sprdemo02.controller;
public class Result {
private Integer code;
private String msg;
private Object data;
public Result() {
}
public Result(Integer code, String msg, Object data) {
this.code = code;
this.msg = msg;
this.data = data;
}
/**
* 获取
* @return code
*/
public Integer getCode() {
return code;
}
/**
* 设置
* @param code
*/
public void setCode(Integer code) {
this.code = code;
}
/**
* 获取
* @return msg
*/
public String getMsg() {
return msg;
}
/**
* 设置
* @param msg
*/
public void setMsg(String msg) {
this.msg = msg;
}
/**
* 获取
* @return data
*/
public Object getData() {
return data;
}
/**
* 设置
* @param data
*/
public void setData(Object data) {
this.data = data;
}
// 响应成功调用
// 这里使用了方法重载,成功的情况分为三种(自定义成功后的消息内容和接口返回的数据,使用默认的success文字和接口返回的数据,还有一种情况只响应成功结果但不需要返回数据)
public static Result success(Object data,String msg){
return new Result(1,msg,data);
}
public static Result success(Object data){
return new Result(1,"success",data);
}
public static Result success(){
return new Result(1,"success",null);
}
// 响应失败调用
// 失败只会有一种情况(自定义提示失败的消息,数据为null)
public static Result error(String msg){
return new Result(0,msg,null);
}
public String toString() {
return "Result{code = " + code + ", msg = " + msg + ", data = " + data + "}";
}
}
三层架构
项目结构
dao daoImpl service serviceImpl controller
dao和service均是接口
daoImpl和serviceImpl和controller是三层架构的核心
daoImpl负责数据访问操作 serviceImpl负责数据的逻辑层处理 controller负责接收数据响应数据
这里我需要实现一个逻辑,运用三层架构的思路实现
浏览器访问参数num为多少,则返回当前传入的num的值+1
1.项目三层架构的结构如下
2.对各层进行代码编写,从前往后写
dao代码如下
package com.jwz.sprdemo02.dao.service.dao.dao;
public interface dao {
public Integer daoA(Integer num);
}
daoImpl代码如下
package com.jwz.sprdemo02.dao.service.dao.dao;
public class daoImpl implements dao{
@Override
public Integer daoA(Integer num) {
// 这里用于对数据进行初始化和访问
// 这里是做demo,我返回的值是传入进来的数据,后期要拿这个传入的参数做数据库查询数据,查询到了返回出去的
return num;
}
}
service代码如下
package com.jwz.sprdemo02.dao.service.dao.service;
public interface service {
public String serviceA(Integer num);
}
serviceImpl代码如下
package com.jwz.sprdemo02.dao.service.dao.service;
import com.jwz.sprdemo02.dao.service.dao.dao.daoImpl;
public class serviceImpl implements service{
// 由于这里service和dao未关联,所以拿不到dao的数据,因此要在这里创建daoImpl的对象,用于拿到数据
private daoImpl dao = new daoImpl();
@Override
public String serviceA(Integer num) {
// 这里用于对数据进行业务的处理
// 例如,调用daoImpl里面的方法,拿到初始化访问到的数据
// 其实这里已经拿到传入的参数值了,我其实可以直接返回这个数据的,但是要演示三层架构功能还是把参数传给dao,让dao返回数据给我们,后期学完数据库后,这些参数传给dao用于进行数据查询,然后会返回查询到的数据,这里就先模拟下,传入num就返回num了,写个注释避免被说多此一举
Integer i = dao.daoA(num);
int sum = i+1;
return "传入的num+1的值是"+sum;
}
}
分层解耦
内聚:软件中各个功能模块内部的功能联系。
耦合:衡量软件中各个层/模块之间的依赖、关联的程度。
软件设计原则:高内聚低耦合。
控制反转: Inyersion OfControl,简称I0C。对象的创建控制权由程序自身转移到外部(容器),这种思想称为控制反转。 依赖注入:DependencyIniection,简称Dl。容器为应用程序提供运行时,所依赖的资源,称之为依赖注入。 Bean对象:I0C容器中创建、管理的对象,称之为bean。
依赖注入和控制反转
上面的三层架构的案例,如果我们的serviceImpl改了个名字比如叫serviceImpl1则controller层的代码也要改变,当项目架构比较大,项目比较多的话,也就相当于所有依赖serviceImpl的类都要去手动修改,使项目变得难以维护,依赖注入控制反转的思想就是将所有的实现类Impl(daoImpl和serviceImpl)的类上面都加个@Component注解,这样的话相当于把所有的实现类都加入到容器内部了,在我们需要创建这个实现类的时候,只需要在这个代码上面加一个@Autowired即可,这样就实现了自动注入,即即使代码改了名,项目都是去容器内部去自动注入的,而改代码的实现类又被加入到容器内部了,相当于可以自动更新了,这样的话项目维护成本就低了
将上面的三层架构的daoImpl和serviceImpl和controller代码进行小小改造,改造如下
daoimpl
package com.jwz.sprdemo02.dao.service.dao.dao;
import org.springframework.stereotype.Component;
@Component //将当前类交给IOC容器管理,成为IOC容器中的bean
public class daoImpl implements dao{
@Override
public Integer daoA(Integer num) {
// 这里用于对数据进行初始化和访问
// 这里是做demo,我返回的值是传入进来的数据
return num;
}
}
serviceImpl
package com.jwz.sprdemo02.dao.service.dao.service;
import com.jwz.sprdemo02.dao.service.dao.dao.dao;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
//将当前类交给IOC容器管理,成为IOC容器中的bean
@Component
public class serviceImpl implements service{
// 由于这里service和dao未关联,所以拿不到dao的数据,因此要在这里创建daoImpl的对象,用于拿到数据
@Autowired //运行时,IOC容器会提供该类型的bean对象,并值给该变依赖注入
private dao dao; // 类型是接口的类型(多态写法)
@Override
public String serviceA(Integer num) {
// 这里用于对数据进行业务的处理
// 例如,调用daoImpl里面的方法,拿到初始化访问到的数据
Integer i = dao.daoA(num); // 1234
int sum = i+1;
return "传入的num+1的值是"+sum; // 1235
}
}
controller
package com.jwz.sprdemo02.dao.service.dao.controller;
import com.jwz.sprdemo02.dao.service.dao.service.service;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
@RestController
public class controller {
// 创建serviceImpl对象
@Autowired //运行时,IOC容器会提供该类型的bean对象,并赋值给该变量 -- 依赖注入
private service s; // 类型是接口类型
// 定义接口,请求和响应数据
@RequestMapping("/helloNum")
public String hello(@RequestParam("num") Integer num) {
String i = s.serviceA(num);
return i;
}
}
@Component的注解有三个不同的衍生注解,@Repository,标注daoImpl数据访问层,@Service标注业务实现层,@Controller标注在数据响应层,建议不属于这三类的层再使用@Component注解,上面的衍生注解功能和@Component一致,主要为了区分业务
Bean注入存在的问题
- @Autowired注解,默认是按照类型进行,如果存在多个相同类型的bean,将会报出如下错误:
可以通过以下方案来解决
-
@Primary (想让哪个Bean生效就在哪个Bean上面价格@Primary,如下
-
package com.jwz.sprdemo02.dao.service.dao.service; import com.jwz.sprdemo02.dao.service.dao.dao.dao; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; @Primary //将当前类交给IOC容器管理,成为IOC容器中的bean @Component public class serviceImpl implements service{ // 由于这里service和dao未关联,所以拿不到dao的数据,因此要在这里创建daoImpl的对象,用于拿到数据 @Autowired //运行时,IOC容器会提供该类型的bean对象,并值给该变依赖注入 private dao dao; // 类型是接口的类型(多态写法) @Override public String serviceA(Integer num) { // 这里用于对数据进行业务的处理 // 例如,调用daoImpl里面的方法,拿到初始化访问到的数据 Integer i = dao.daoA(num); // 1234 int sum = i+1; return "传入的num+1的值是"+sum; // 1235 } }
-
-
@Qualifier(在使用bean时上面价格@Qualifier注解,表明使用哪个bean,如下)
-
package com.jwz.sprdemo02.dao.service.dao.controller; import com.jwz.sprdemo02.dao.service.dao.service.service; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.RestController; @RestController public class controller { // 创建serviceImpl对象 @Qualifier("serviceImpl") // bean名字,不指定的话默认类名首字母小写 @Autowired //运行时,IOC容器会提供该类型的bean对象,并赋值给该变量 -- 依赖注入 private service s; // 类型是接口类型 // 定义接口,请求和响应数据 @RequestMapping("/helloNum") public String hello(@RequestParam("num") Integer num) { String i = s.serviceA(num); return i; } }
-
-
@Resource(功跟autowire一样,只是autowire是自动注入,而Resource是根据Bean名称进行注入的)
-
package com.jwz.sprdemo02.dao.service.dao.controller; import com.jwz.sprdemo02.dao.service.dao.service.service; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.RestController; @RestController public class controller { // 创建serviceImpl对象 @Resource(name = "serviceImpl") // bean名字,不指定的话默认类名首字母小写 private service s; // 类型是接口类型 // 定义接口,请求和响应数据 @RequestMapping("/helloNum") public String hello(@RequestParam("num") Integer num) { String i = s.serviceA(num); return i; } }
-
Mysql相关
mysql所有相关命令
-- 终端连接远程mysql命令
-- mysql -h远程地址 -P端口号 -u用户名 -p密码
mysql -h139.196.214.124 -P3306 -uceshaiaa -pxtZA8p7xEKBWLd6Wnd
-- 一:DDL部分相关命令(下述语法中的database,也可以替换成schema。如:create schema db01;select schema();)
-- 1:数据库操作
-- 1.1 查询
-- 1.1-1 查询所有的数据库
show databases;
-- 1.1-2 查询当前数据库
select database();
-- 1.2 使用
-- 1.2-1 使用数据库
use 数据库名;
-- 1.3 创建
-- 1.3-1 创建数据库(if not exists这是可选的,如果加上则代表:数据库存在不会报错也不会做任何操作,如果数据库不存在则会去创建)
create database [ if not exists ] 数据库名;
-- 1.4 删除
-- 1.4-1 删除数据库(if exists是可选参数,数据库不存在则不会做任何操作,也不会报错,如果存在就会去执行删除数据库操作)
drop database [ if exists ] 数据库名;
-- 2:表操作(带[]的都是可选参数)
-- 2.1 创建表
create table 表名(字段1 字段类型 [约束] [comment 字段1注释],.....,字段n 字段类型 [约束] [comment 字段n注释])[comment 表注释];
-- 2.1-1 示例(id主键自增,用户名非空且唯一,姓名非空,性别默认为男,都是加了约束的)
create table user(
id int primary key auto_increment comment 'ID字段,唯一标识',
username varchar(20) not null unique comment '用户名',
name varchar(10) not null comment '姓名',
age int comment '年龄',
gender char(1) default '男' comment '性别'
) comment '用户表';
-- 2.2 查询表
-- 2.2-1 查询当前数据库的所有表
show tables;
-- 2.2-2 查询表结构
desc 表名;
-- 2.2-3 查询建表语句
show create table 表名;
-- 2.3 添加
-- 2.3-1 添加表字段
alter table 表名 add 字段名 类型(长度)[comment 注释][约束];
-- 2.4 修改
-- 2.4-1 修改表字段类型
alter table 表名 modify 字段名 新数据类型(长度);
-- 2.4-2 修改表字段和字段类型
alter table 表名 change 旧字段名 新字段名 类型(长度)[comment 注释] [约束];
-- 2.5 删除
-- 2.5-1 删除字段
alter table 表名 drop column 字段名;
-- 2.5-2 删除表
drop table [if exists] 表名;
-- 2.6 修改
-- 2.6-1 修改表名
rename table 表名 to 新表名;
-- 二:DML部分相关命令
-- 1.insert语法(添加数据sql语句)
-- 注意:插入的表内如果有非空字段的话记得给个默认值,下面是个示例代码,开始和结束时间都是非空字段,即使不想修改也要给个默认值,开始和结束时间的获取使用now()(带时分秒)和data()(不带时分秒)去获取时间
-- 示例代码:insert into tb emp (username, name,gender,create time,update time) values ('wuji',"张忌',1,now(),now());
-- 1.1 指定字段添加数据
insert into 表名 (字段名1,字段名2,...) value (值1,值2,...)
-- 1.2 全部字段添加数据
insert into 表名 values (值1,值2,...)
-- 1.2-1 如果对于有的字段不想去设置可以给null补位即可(如下:Id是自增的,不需要插入id,因此给null补位即可)
insert into tb_emp values (null,"zhiruo2","周芷者","2","1.jpg","123",1,"2010-01-01",now(),now())
-- 1.3 批量添加数据(指定字段):
insert into 表名 (字段名1,字段名2,...) values (值1,值2,...),(值1,值2,...),...
-- 1.4 批量添加数据(全部字段):
insert into 表名 values (值1,值2,...),(值1,值2,...),...
-- 2.update语法(修改数据的sql语句)
-- 2-1 注意如果记录里面需要记录修改时间的话,需要在每次的修改语句里面重新获取下当前值并做修改
-- 示例:update tb_emp set name='张三',update_time=now() where id=1;
update 表名 set 字段名1=值1,字段名2=值2,...[where 条件];
-- 示例:将整张表的开始时间都更新为2010-01-01,最后修改时间为当前时间(即不指定where条件就是更新整张表)
-- update tb_emp set entrydate='2010-01-01',update_time = now();
-- 3.delete语法(删除数据的sql语句)
-- 3.1 不写条件的话就是删除整张表数据
-- 示例:delete from tb_emp where id = 1; // 删除id为1的这条数据
delete from 表名 [where 条件];
-- 批量删除语法
delete from 表名 where id in (主键id1,主键id2,主键id3,...);
-- 三:DQL部分相关命令
-- DQL基本格式和顺序如下
select 字段列表 from 表名列表 where 条件列表 group by 分组字段列表 having 分组后条件列表 order by 排序字段列表 limit 分页参数
-- 1. 基本查询
-- 1.1-1 查询多个字段
select 字段1,字段2,字段3 from 表名;
-- 1.1-2 查询所有字段(通配符)
select*from 表名;
-- 1.1-3 设置别名
select 字段1 as 别名1,字段2 as 别名2 from 表名;
-- PS:as关键字可省略,如下
select 字段1 别名1,字段2 别名2 from 表名;
-- 1.1-4 去除某个字段的数据的重复记录
select distinct 字段名 from 表名;
-- 2. 条件查询
-- 条件列表字段如下:
-- < , <= , > , >= , = , <>或者!= , between...and... 在某个范围之内 , in(...) 在in之后列表中的值 多选1 , like 占位符(模糊匹配(_匹配单个字符,%匹配任意个字符)) , is null (是null), is not null (不是null) , and或&& , or或者|| , not或者!
select 字段列表 from 表名 where 条件列表;
-- 示例
-- 查询id小于等于5的所有数据
select * from tb_emp where id <= 5;
-- 查询姓名为萧寂的数据
select * from tb_emp where name = '萧寂';
-- 查询日期范围在'2000-01-01'到'2010-01-01'之间的所有数据
select * from tb_emp where entrydate >= '2000-01-01' and entrydate <= '2010-01-01'
-- 查询日期在'2000-01-01'到'2010-01-01'之间,且性别为2的所有数据
select * from tb_emp where entrydate between '2000-01-01' and '2010-01-01' and gender = 2;
-- 查询字段job或等于2或等于3或等于4的所有数据的两种方法
select * from tb_emp where job = 2 or job = 3 or job = 4;
select * from tb_emp where job in (2,3,4);
-- 查询姓名为两个字的所有数据
select * from tb_emp where name like '__'; -- 单个下划线匹配单个字符,这里用了两个下划线
-- 查询姓名为张的数据
select * from tb_emp where name like '张%'; -- %代表任意字符,这个代表只要姓张就行,后面无所谓
-- 3. 聚合函数
-- 3.1-1 聚合函数列表如下
-- count 统计数量 , max 最大值 , min 最小值 , avg 平均值 , sum 求和
select 聚合函数(字段列表) from 表名;
-- 示例代码如下:
-- 统计查询的字段的的总数量(如果查出来的数据有null的话,则不计入总条数)
select count(id) from tb_emp;
-- 统计整张表的行数的数量(推荐)
select count(*) from tb_emp;
-- 统计年龄最大值
select max(age) from tb_emp;
-- 统计年龄最小值
select min(age) from tb_emp;
-- 统计年龄平均值
select avg(age) from tb_emp;
-- 统计年龄的和
select sum(age) from tb_emp;
-- 4. 分组查询
select 字段列表 from 表名 [where 条件] group by 分组字段名 [having 分组后过滤条件];
-- 示例代码:
-- 根据性别分组,统计1男性和女性员工的数量
select gender,count(*) from tb_emp group by gender; -- 直接将结果根据gender进行了分组并统计了数量(查询的数据会显示两列,第一列是gender的数据,第二列就是count统计的当前gender数据的总数量)
-- 先查询时间在'2015-01-01'(包含)以前的数据,并对结果根据职位分组,获取员工数量大于等于2的职位
select job,count(*) from tb_emp where entrydata <= '2015-01-01' group by job having count(*) >=2; -- 在where后不能跟聚合函数,可以加个having后面可以加上分组后的过滤条件,having后面是根据前面查询出来的分组数据做一下值>=2的一个筛选,简单来说就是先分组再展示然后再筛选
-- 5. 排序查询
select 字段列表 from 表名 [where 条件列表] [group by 分组字段] order by 字段1 排序方式1,字段2 排序方式2,...
-- 5.1-1 示例
-- ASC 升序(默认) , DESC 降序
-- 代码,根据时间降序排序
select * from tb_emp order by entrydate desc;
-- 根据开始时间进行升序排序,如果开始时间相同则根据更新时间降序排序(即当前一个排序方式碰到相同值时会触发下一个排序规则)
select * from tb_emp order by entrydate , update_Time desc;
-- 6. 分页排序
select 字段列表 from 表名 limit 起始索引,查询记录数;
-- 示例代码
-- 起始索引是0,每页展示5条数据
select * from tb_emp limit 0,5
-- 查询第一页数据,每页展示5条数据
select * from tb_emp limit 0,5
-- 查询第二页数据,每页展示5条数据
select * from tb_emp limit 5,5
-- 查询第三页数据,每页展示5条数据
select * from tb_emp limit 10,5
-- 查询第n页数据,每页展示m条数据
select * from tb_emp limit (n-1)*m,m
-- 四:多表设计相关
-- 1. 一对多(员工和部门之间的关系)
-- 创建两张表,一张员工表和一张部门表,员工表有个字段dept_id与部门表的id相对应(员工表是多,部门表是一,多个员工可以属于同一个部门,但是一个员工只能选择一个部门)
-- 部门数据可以直接删除,然而还有部分员工归属于该部门下,此时就出现了数据的不完整、不一致问题。这里就需要使用外键了
-- 1.1-1 添加物理外键方式(影响增删改效率和其他方面的缺点,不推荐,推荐使用1.1-2的逻辑外键方式)
-- 创建表时添加
create table user(
...;
dept_id int not null comment '外键',
[constraint] [外键名称] foreign key (外键字段名) references 主表 (字段名)
) comment '用户表';
-- 创建完表后,执行下面命令添加
alter table 表名 add constraint 外键名 foreign key (外键字段名) references 主表 (字段名);
-- 示例代码
alter table tb_emp add constraint tb_emp_fk_dept_id foreign key (dept_id) references tb_dept (id);
-- 1.1-2 添加逻辑外键方式
-- 在业务层逻辑中,解决外键关联。(在后端代码中体现,通过后端代码体现)
-- 2.一对一(身份证和人之间的关系)
-- 一对一关系,多用于单表拆分,将一张表的基础字段放在一张表中,其他字段放在另一张表中,以提升操作效率(在任意一方添加外键关联另一张表的主键,将外键设置为唯一的即可)
select * from 表1,表2 where 表1.外键字段 = 表2.主键id;
-- 3.多对多(老师和学生的关系,学生和课程的关系)
-- 提供一个中间表,中间表至少包含两个外键,分别关联两方主键
-- 中间表建表语句如下
create table tb_student_course(
id int primary key auto_increment comment '主键自增',
student_id int not null comment '学生ID',
course_id int not null comment '课程ID',
constraint fk_courseid foreign key (course_id) references tb_course (id),
constraint fk_studentid foreign key (student_id) references tb_student (id)
)comment '学生课程中间表'
-- 示例代码
select * from 表1,中间表,表3 where 表1.外键字段 = 中间表.主键id and 中间表.表3_id = 表3.id;
-- 五:多表查询
-- 语法格式如下:
select * from 表1,表2 where 表1.外键字段 = 表2.主键id;
-- 起别名
select * from 表1 a1 , 表2 a2 where a1.外键字段 = a2.主键id;
-- 示例代码
select * from tb_emp a1 , tb_dept a2 where a1.dept_id = a2.id;
-- 1. 内连接查询(相当于A,B交集部分数据)
-- 隐式内连接:select 字段列表 from 表1,表2 where 条件...;
-- 示例代码(跟上面的示例代码一样)
select * from tb_emp a1 , tb_dept a2 where a1.dept_id = a2.id;
-- 直接展示两个表里面的某些字段,示例代码如下
select a1.name,a2.name from tb_emp a1 , tb_dept a2 where a1.dept_id = a2.id;
-- 显式内连接:select 字段列表 from 表1 [inner] join 表2 on 连接条件...;
-- 下面的示例代码和上面的隐式内连接示例相同
select tb_emp.name,tb_dept.name from tb_emp inner join tb_dept on tb_emp.dept_id = tb_dept.id;
-- 2. 外连接查询
-- 2.1 左外连接(查询左表所有数据,包括两张表交集部分数据)(这里表1就是相当于左表)
select 字段列表 from 表1 left [outer] join 表2 on 连接条件...;
select e.name, d.name from tb_emp e left join tb_dept d on e.dept_id = d.id;
-- 2.2 右外连接(查询右表所有数据,包括两张表交集部分数据)(这里表1就是相当于右表)
select 字段列表 from 表1 right [outer] join 表2 on 连接条件...;
select e.name, d.name from tb_emp e right join tb_dept d on e.dept_id = d.id;
-- 3. 子查询
-- SQL语句中嵌套select语句,称为嵌套查询,又称子查询。
select * from tl where column1 = (select column1 from t2 ...);
-- 子查询外部的语句可以是insert/update/delete/select 的任何一个,最常见的是 select。
-- 分类:
-- 3.1标量子查询:子查询返回的结果为单个值
-- 子查询返回的结果是单个值(数字、字符串、日期等),最简单的形式
-- 常用的操作符:= , <> , > , >= , < , <=
-- 例如我要删除某个数据,需要先获取到这个数据的id,但是目前只知道这个数据的name值,因此需要先根据name值查出这个数据的id,然后再进行删除
delete from 表名 where id = (select id from 表名 where name = "小明");
-- 3.2 列子查询:子查询返回的结果为一列
-- 子查询返回的结果是一列(可以是多行)
-- 常用的操作符:in、notin等
-- 例如要查询两个部门的所有的员工信息(1.查询两个部门的部门id,根据部门id查询对应的员工信息)
select id from tb_dept where name = '教研部' or name = '咨询部' -- 2,3
select * from tb_emp where dept_id in (2,3);
-- 将上面两个进行合并
select * from tb_emp where dept_id in (select id from tb_dept where name = '教研部' or name = '咨询部')
-- 3.3 行子查询:子查询返回的结果为一行
-- 子查询返回的结果是一行(可以是多列)。
-- 常用的操作符:=、<>、 in、not in
-- 查询与'萧寂'的入职日期和职位都相同的员工信息
-- 先查询'萧寂'数据
select entrydate,job from 表名 where name = '萧寂' -- 2007-01-01 2
-- 查询与其入职日期和职位都相同的员工信息
select * from tb_emp where entrydate = '2007-01-01' and job = 2;
-- 将上面两个合并为一个
select * from tb_emp where entrydate = (select entrydate from 表名 where name = '萧寂') and job = (select job from 表名 where name = '萧寂');
-- 简化形式
select * from tb_emp where (entrydate,job) = ( select entrydate,job from 表名 where name = '萧寂');
-- 3.4 表子查询:子查询返回的结果为多行多列
-- 子查询返回的结果是多行多列,常作为临时表
-- 常用的操作符:in
-- 查询入职日期是'2006-01-01'之后的员工信息,及其部门名称
-- 先查询入职日期是'2006-01-01'之后的员工信息
select * from tb_emp where entrydate >'2006-01-01';
-- 查询这部分员工及其部门名称(e.*代表显示员工表的所有数据,d.name代表只显示部门表名称)
select e.*,d.name from (select * from tb_emp where entrydate >'2006-01-01') e,tb_dept d where e.dept_id = d.id;
-- 六: 事务
-- 开启事务:start transaction;/ begin;
-- 提交事务:commit;
-- 回滚事务:rollback;
start transaction;
sql语句...
sql语句...
commit;
rollback;
-- 这样两个sql语句就被捆绑在一起了,如果有任意一个执行不成功,则另外一个也不会成功,不会被提交的
-- 七: 索引(索引(index)是帮助数据库 高效获取数据 的 数据结构)
-- 创建索引
create [unique] index 索引名 on 表名(字段名,...);
-- 查看索引
show index from 表名;
-- 删除索引
drop index 索引名 on 表名;
-- 缺点:占用存储空间 提高查找效率,降低了增删改的效率
-- 当有600万个数据,执行下面的sql语句就会显得特别耗时
select * from 表名 where sn = '111'
-- 优化方式:加索引(如下)
-- 示例
create index sn_index on tb_sku(sn)
-- 执行完创建索引的代码,再次执行上面的查询代码,会发现查询基本瞬间完成
-- 主键字段,在建表时,会自动创建主键索引。
-- 添加唯一约束时,数据库实际上会添加唯一索引。
数据类型
DDL
- DDL英文全称是 Data Definition Language,数据定义语言,用来定义数据库对象(数据库、表)。
数据库操作
-- 一:DDL部分相关命令(数据库操作)
-- 1.1 查询
-- 1.1-1 查询所有的数据库
show databases;
-- 1.1-2 查询当前数据库
select database();
-- 1.2 使用
-- 1.2-1 使用数据库
use 数据库名;
-- 1.3 创建
-- 1.3-1 创建数据库
create database [ if not exists ] 数据库名;
-- 1.4 删除
-- 1.4-1 删除数据库
drop database [ if exists ] 数据库名;
表操作(创建,查询,修改,删除)
约束:
- 概念:约束是作用于表中字段上的规则,用于限制存储在表中的数据
- 目的:保证数据库中数据的正确性、有效性和完整性。
非空约束 限制该字段值不能为null not null
唯一约束 保证字段的所有数据都是唯一、不重复的 unique
主键约束 主键是一行数据的唯一标识,要求非空且唯一 primary key(auto_increment 自增)
默认约束 保存数据时,如果未指定该字段值,则采用默认值 default
外键约束 让两张表的数据建立连接,保证数据的一致性和完整性 foreign key
示例创建表语句
create table user(
id int primary key comment 'ID字段,唯一标识',
username varchar(20) not null unique comment '用户名',
name varchar(10) not null comment '姓名',
age int comment '年龄',
gender char(1) default '男' comment '性别'
) comment '用户表';
表操作增删改
添加字段:alter table 表名 add 字段名 类型(长度)[comment 注释][约束];
修改字段类型:alter table 表名 modify 字段名 新数据类型(长度);
修改字段名和字段类型:alter table 表名 change 旧字段名 新字段名 类型(长度)[comment 注释] [约束];
删除字段:alter table 表名 drop column 字段名;
修改表名: rename table 表名 to 新表名;
删除表:drop table [if exists] 表名;
DML
- DML英文全称是Data Manipulation Language(数据操作语言),用来对数据库中表的数据记录进行增、删、改操作。
- 具体sql语句看上面
DQL
select 字段列表 from 表名列表 where 条件列表 group by 分组字段列表 having 分组后条件列表 order by 排序字段列表 limit 分页参数
条件列表所有字段
聚合函数
- 介绍:将一列数据作为一个整体,进行纵向计算。
- 语法:select 聚合函数(字段列表) from 表名;
分组查询
where与having区别
- 1.执行时机不同:where是分组之前进行过滤,不满足where条件,不参与分组;而having是分组之后对结果进行过滤
- 2.判断条件不同:where不能对聚合函数进行判断,而having可以。
多表操作
- 相互关联,所以各个表结构之间也存在着各种联系,基本上分为三种: 项目开发中,在进行数据库表结构设计时,会根据业务需求及业务模块之间的关系,分析并设计表结构,由于业务之间
MyBatis
- MyBatis是一款优秀的 持久层 框架,用于简化JDBC的开发。
[官方网站][mybatis.org/mybatis-3/z…]
Mybatis入门
使用Mybatis查询所有用户数据
准备工作
- (创建springboot工程、数据库表user、实体类User)
- 引入Mybatis的相关依赖,配置Mybatis
- 编写SQL语句(注解/XML)
创建项目
创建项目只勾选SQL->Mybatis Framework 和 MySQL Driver这两个依赖(这个demo项目不用勾选web -> Spring web) 直接点击完成
可以删除多余文件(.idea , .gitignore , HELP.md , mvnw , mvnw.cmd)
在项目的src/main/resource/application.properties加入以下数据库连接代码
# 驱动类名称
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
# 数据库连接的url,最后一个单词是数据库名称
spring.datasource.url=jdbc:mysql://localhost:3306/user
# 连接数据库的用户名
spring.datasource.username=root
# 连接数据库的密码
spring.datasource.password=admin
创建实体类,字段名和数据库字段名要一一对应
package com.jwz.entity;
public class User {
private Integer id; // id字段
private String username; // 姓名
private Integer age; // 年龄
public User() {
}
public User(Integer id, String username, Integer age) {
this.id = id;
this.username = username;
this.age = age;
}
/**
* 获取
* @return id
*/
public Integer getId() {
return id;
}
/**
* 设置
* @param id
*/
public void setId(Integer id) {
this.id = id;
}
/**
* 获取
* @return username
*/
public String getUsername() {
return username;
}
/**
* 设置
* @param username
*/
public void setUsername(String username) {
this.username = username;
}
/**
* 获取
* @return age
*/
public Integer getAge() {
return age;
}
/**
* 设置
* @param age
*/
public void setAge(Integer age) {
this.age = age;
}
public String toString() {
return "User{id = " + id + ", username = " + username + ", age = " + age + "}";
}
}
创建Mapper层(原dao层)
package com.jwz.mapper;
import com.jwz.entity.User;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Select;
import java.util.List;
@Mapper // 在运行时,会自动生成该接口的实现类对象(代理对象),并且将该对象交给I0C容器管理
public interface UserMapper {
// 查询用户信息(因为查询会返回多条数据,因此使用集合进行封装)
// 参数就是sql语句
@Select("select * from student")
public List<User> list();
}
在src/test/java/包名/MybatisApplicationTests 内加入以下代码进行测试
package com.jwz;
import com.jwz.entity.User;
import com.jwz.mapper.UserMapper;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import java.util.List;
@SpringBootTest // SpringBoot整合单元测试的注解
class MybatisApplicationTests {
@Autowired
private UserMapper userMapper;
@Test
void contextLoads() {
// 调用方法进行查询
List<User> usetList = userMapper.list();
// 将查询到的结果通过stream流打印
usetList.stream().forEach(user->{
System.out.println(user);
});
}
}
idea配置sql语句提示
上面的项目可以发现写sql语句时,并没有提示,需要手打,很不友好,接下来配置一下idea的提示吧
- 1.选中上面的sql右键
- 2.选择Show Context Actions
- 3.再次选择Inject language or reference
- 4.选择列表的Mysql,选择即可
- 5.保存
- 6.在@Select("")在里面写sql语句就会显示提示了
上面虽然是有了提示,但是编辑器不识别表信息,不认识表名,因此会爆红,按照下面接着配置
- 产生原因:ldea和数据库没有建立连接,不识别表信息
- 解决方式:在Idea中配置MySOL数据库连接
操作步骤如下
- 1.点击Idea右边的数据库图标
- 2.点击+号,选择数据源,添加Mysql数据库
- 3.输入用户名和密码以及数据库名
- 4.点击应用开始将idea与数据库进行连接
- 5.连接完成后,查看代码,发现不会报错了,并且表名也会有对应的提示了
按照如上配置完成后,sql语句就会有提示了,并且sql语句单词写错了还有对应的爆红提示
切换连接池
目前SpringBoot默认使用的是Hikari连接池(查看连接池信息可以查看项目运行后的最后几行打印日志,里面包含连接池的完全限定名)
切换连接池就两个步骤
1.在上面src/main/resource/application.properties的文件内新增type字段,指定使用哪个连接池,不指定就使用默认的Hikari
# 例如我要使用Druid(德鲁伊)连接池,后面的值是当前连接池的完全限定名,使用哪个连接池就换成哪个连接池的完全限定名即可
spring.datasource.type=com.alibaba.druid.pool.DruidDataSource
2.在项目的pom.xml新增Druid的maven插件代码
[][[Maven Repository: Search/Browse/Explore (mvnrepository.com)]这个是Maven插件官网,不会写的可以去查
<!-- https://mvnrepository.com/artifact/com.alibaba/druid -->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid</artifactId>
<version>1.2.22</version>
</dependency>
只需要以上两步就可以任意切换项目的连接池了
lombok工具包介绍
- Lombok是一个实用的]ava类库,能通过注解的形式自动生成构造器、getter/setter、equals、hashcode、tostring 等方法,并可以自动化生成日志变量,简化java开发、提高效率。
| 注解 | 作用 |
|---|---|
| @Getter/@Setter | 为所有的属性提供get/set方法 |
| @ToString | 会给类自动生成易阅读的 toString 方法 |
| @EqualsAndHashCode | 根据类所拥有的非静态字段自动重写 equals 方法和 hashCode 方法 |
| @Data | 提供了更综合的生成代码功能(@Getter+@Setter+@ToString+@EqualsAndHashcode) |
| @NoArgsConstructor | 为实体类生成无参的构造器方法 |
| @AllArgsConstructor | 为实体类生成除了static修饰的字段之外带有各参数的构造器方法 |
使用方式
1. 在pom.xml里面引入lombok的依赖
在pom.xml里面新增依赖包(这里无需指定版本号,因为在SpringBoot工程里面已经将lombok版本进行了统一管理,这里我们只需要引入即可)
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</dependency>
2.在实体类中直接使用即可
package com.jwz.entity;
import lombok.*;
// @Data // @Data等同于@Getter和@Setter和@ToString和@EqualsAndHashCode
@Getter // 为所有属性提供get方法
@Setter // 为所有属性提供set方法
@ToString // 重写tostring方法
@EqualsAndHashCode // 重写equals和hashcode方法
@AllArgsConstructor // 生成除了static修饰的字段之外的有参构造方法
@NoArgsConstructor // 生成无参的构造方法
public class User {
private Integer id;
private String username;
private Integer age;
}
然后直接测试使用即可
Mybatis基础操作(完成业务的增删改查)
准备工作
- 准备数据库表 emp
- 创建一个新的springboot工程,选择引入对应的起步依赖(mybatis、mysql驱动、lombok)
- application.properties中引入数据库连接信息
- 创建对应的实体类 Emp(实体类属性采用驼峰命名)
- 准备Mapper接口 EmpMapper
1.准备数据库表
SQL的建表语句
-- 部门管理
create table dept(
id int unsigned primary key auto_increment comment '主键ID',
name varchar(10) not null unique comment '部门名称',
create_time datetime not null comment '创建时间',
update_time datetime not null comment '修改时间'
) comment '部门表';
insert into dept (id, name, create_time, update_time) values(1,'学工部',now(),now()),(2,'教研部',now(),now()),(3,'咨询部',now(),now()), (4,'就业部',now(),now()),(5,'人事部',now(),now());
-- 员工管理
-- date只有年月日 datetime 包含年月日时分秒
create table emp (
id int unsigned primary key auto_increment comment 'ID',
username varchar(20) not null unique comment '用户名',
password varchar(32) default '123456' comment '密码',
name varchar(10) not null comment '姓名',
gender tinyint unsigned not null comment '性别, 说明: 1 男, 2 女',
image varchar(300) comment '图像',
job tinyint unsigned comment '职位, 说明: 1 班主任,2 讲师, 3 学工主管, 4 教研主管, 5 咨询师',
entrydate date comment '入职时间',
dept_id int unsigned comment '部门ID',
create_time datetime not null comment '创建时间',
update_time datetime not null comment '修改时间'
) comment '员工表';
INSERT INTO emp
(id, username, password, name, gender, image, job, entrydate,dept_id, create_time, update_time) VALUES
(1,'jinyong','123456','金庸',1,'1.jpg',4,'2000-01-01',2,now(),now()),
(2,'zhangwuji','123456','张无忌',1,'2.jpg',2,'2015-01-01',2,now(),now()),
(3,'yangxiao','123456','杨逍',1,'3.jpg',2,'2008-05-01',2,now(),now()),
(4,'weiyixiao','123456','韦一笑',1,'4.jpg',2,'2007-01-01',2,now(),now()),
(5,'changyuchun','123456','常遇春',1,'5.jpg',2,'2012-12-05',2,now(),now()),
(6,'xiaozhao','123456','小昭',2,'6.jpg',3,'2013-09-05',1,now(),now()),
(7,'jixiaofu','123456','纪晓芙',2,'7.jpg',1,'2005-08-01',1,now(),now()),
(8,'zhouzhiruo','123456','周芷若',2,'8.jpg',1,'2014-11-09',1,now(),now()),
(9,'dingminjun','123456','丁敏君',2,'9.jpg',1,'2011-03-11',1,now(),now()),
(10,'zhaomin','123456','赵敏',2,'10.jpg',1,'2013-09-05',1,now(),now()),
(11,'luzhangke','123456','鹿杖客',1,'11.jpg',5,'2007-02-01',3,now(),now()),
(12,'hebiweng','123456','鹤笔翁',1,'12.jpg',5,'2008-08-18',3,now(),now()),
(13,'fangdongbai','123456','方东白',1,'13.jpg',5,'2012-11-01',3,now(),now()),
(14,'zhangsanfeng','123456','张三丰',1,'14.jpg',2,'2002-08-01',2,now(),now()),
(15,'yulianzhou','123456','俞莲舟',1,'15.jpg',2,'2011-05-01',2,now(),now()),
(16,'songyuanqiao','123456','宋远桥',1,'16.jpg',2,'2010-01-01',2,now(),now()),
(17,'chenyouliang','123456','陈友谅',1,'17.jpg',NULL,'2015-03-21',NULL,now(),now());
注意:员工表绑定的有部门id,因此多创建了个部门表,实际操作中用不到部门表
2. 创建一个新的springboot工程,选择引入对应的起步依赖(mybatis、mysql驱动、lombok)
1. 创建项目只勾选SQL->Mybatis Framework 和 MySQL Driver这两个依赖(这个demo项目不勾选web -> Spring web) 直接点击完成(可以删除多余文件(.idea , .gitignore , HELP.md , mvnw , mvnw.cmd))
2. 在项目的pom.xml文件出入lombok插件代码
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</dependency>
3. application.properties中引入数据库连接信息
# 驱动类名称(这里不指定type了,使用默认的连接池)
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
# 数据库连接的url,最后一个单词是数据库名称
spring.datasource.url=jdbc:mysql://localhost:3306/user
# 连接数据库的用户名
spring.datasource.username=root
# 连接数据库的密码
spring.datasource.password=admin
4. 创建对应的实体类Emp(实体类属性采用驼峰命名)
package com.jwz.entity;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.time.LocalDate;
import java.time.LocalDateTime;
@Data
@NoArgsConstructor
@AllArgsConstructor
public class Emp {
private Integer id;
private String username;
private String password;
private String name;
private Short gender;
private String image;
private Short job;
private LocalDate entrydate; // 只包含年月日
private Integer deptId; // 数据库采用dept_id这种下划线形式,在实体类采用驼峰命名法
private LocalDateTime createTime; // 包含年月日时分秒
private LocalDateTime updateTime;
}
5. 准备Mapper接口EmpMapper
第一种方式使用注解实现增删改查功能
package com.jwz.mapper;
import com.jwz.entity.Emp;
import org.apache.ibatis.annotations.*;
import java.time.LocalDate;
import java.util.List;
@Mapper
public interface EmpMapper {
// 根据Id删除数据(#{}是mybatis提供的可以获取到接收的参数,这样实现了调用方法传入多少的ID就删除哪个ID的数据)
// 返回值int记录的是数据库变动的行数,0为失败了,1为变动了一行代表删除成功了
// 不需要返回值的话将int改为void即可
// 如果mapper接口方法形参只有一个普通类型的参数,#{}里面的属性名可以随便写,如:#{id}、#{value}。
@Delete("delete from emp where id = #{id}")
public int deleteEmp(Integer id);
// 新增员工
// 将员工表作为参数传递进来,此时#{}里面填写的是员工表的对应的字段进行占位
// 在多表查询的情境中,我们一张表要关联另一张表的主键ID,但是新增语句中,新增完了获取id发现是个null,拿不到主键id,因为主键是ID自增,不需要我们手动添加,下面就是获取到主键id的方法
// 只需要加个Options,参数一代表将主键保存到实体类的id属性上,参数二代表需要拿到生成的主键值
@Options(keyProperty = "id", useGeneratedKeys = true)
@Insert("insert into emp(username, name, gender, image, job, entrydate, dept_id, create_time, update_time) values (#{username},#{name},#{gender},#{image},#{job},#{entrydate},#{deptId},#{createTime},#{updateTime})")
public int insertEmp(Emp emp);
// 修改员工
@Update("update emp set username=#{username}, name=#{name}, gender=#{gender}, image=#{image}, job=#{job}, entrydate=#{entrydate}, dept_id=#{deptId}, update_time=#{updateTime} where id=#{id}")
public int updateEmp(Emp emp);
// 查询员工
// 根据id查询(这样查询的结果始终只有一个,因此返回值为员工对象即可)
@Select("select id, username, password, name, gender, image, job, entrydate, dept_id, create_time, update_time from emp where id=#{id}")
public Emp getById(Integer id);
// 上面的查询会发现deptId,createTime,updateTime的值都为null,因为数据库这些都是下划线的,这些字段名未和数据库完全保持一致,因此为null了
// 实体类属性名 和 数据库表查询返回的字段名一致,mybatis会自动封装。
// 如果实体类属性名 和 数据库表查询返回的字段名不一致,不能自动封装。值会为null
// 解决方案一:
// 给字段起别名,让别名和实体类属性保持一致(不能使用*了)
@Select("select id,username,password,name,gender,image,job,entrydate,dept_id deptId,create_time createTime,update_time updateTime from emp where id = #{id}")
public Emp getByIdTwo(Integer id);
// 解决方法二:
// 通过@Results, @Result注解手动映射封装
@Results({@Result(column = "dept_id", property = "deptId"), @Result(column = "create_time", property = "createTime"), @Result(column = "update_time", property = "updateTime")})
@Select("select id, username, password, name, gender, image, job, entrydate, dept_id, create_time, update_time from emp where id=#{id}")
public Emp getByIdThree(Integer id);
// 解决方案三:
// 开启mybatis的驼峰命名自动映射开关 a_column -> aColumn
// 在application.properties里面配置下面这一行代码即可,然后重新运行getById方法
// mybatis.configuration.map-underscore-to-camel-case=true
// 条件查询(返回值可能有多个,使用list进行了封装)
// 根据输入的年龄,性别,时间范围搜索数据,并且姓名支持模糊查询,性别精确查询,时间是范围查询,支持分页查询,并对查询的结果进行倒序排序
// concat字符串拼接,mysql提供的函数
@Select("select * from emp where name like concat('%',#{name},'%') and gender = #{gender} and entrydate between #{begin} and #{end} order by update_time desc")
public List<Emp> list(String name, Short gender, LocalDate begin, LocalDate end);
}
测试
package com.jwz;
import com.jwz.entity.Emp;
import com.jwz.mapper.EmpMapper;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.util.List;
@SpringBootTest
class MyBatisEmpDemoApplicationTests {
@Autowired
private EmpMapper empMapper;
// 删除员工
@Test
public void testDelete() {
// 删除id为16的数据
int i = empMapper.deleteEmp(15);
if (i == 0) {
System.out.println("删除失败");
} else {
System.out.println("删除成功,数据库影响了" + i + "行");
}
}
// 新增员工
@Test
public void testInsert(){
//创建员工对象
Emp emp = new Emp();
emp.setUsername("tom1");
emp.setName("汤姆1");
emp.setImage("1.jpg");
emp.setGender((short)1);
emp.setJob((short)1);
emp.setEntrydate(LocalDate.of(2000,1,1));
emp.setCreateTime(LocalDateTime.now());
emp.setUpdateTime(LocalDateTime.now());
emp.setDeptId(1);
//调用添加方法
int i = empMapper.insertEmp(emp);
if(i == 0){
System.out.println("添加失败");
}else{
System.out.println("添加成功,数据库影响了"+i+"行");
System.out.println("主键id为:"+emp.getId());
}
}
// 修改员工
@Test
public void testUpdate(){
//要修改的员工信息
Emp emp = new Emp();
emp.setId(20);
emp.setUsername("songdaxia");
emp.setPassword(null);
emp.setName("老宋");
emp.setImage("2.jpg");
emp.setGender((short)1);
emp.setJob((short)2);
emp.setEntrydate(LocalDate.of(2012,1,1));
emp.setCreateTime(null);
emp.setUpdateTime(LocalDateTime.now());
emp.setDeptId(2);
//调用方法,修改员工数据
int i = empMapper.updateEmp(emp);
if(i == 0){
System.out.println("修改失败");
}else{
System.out.println("修改成功,数据库影响了"+i+"行");
System.out.println("主键id为:"+emp.getId());
}
}
// 根据id查询员工
@Test
public void testGetById(){
// 未起别名的(并且未配置驼峰命名开关的)
// Emp emp = empMapper.getById(4);
// Emp(id=4, username=weiyixiao, password=123456, name=韦一笑, gender=1, image=4.jpg, job=2, entrydate=2007-01-01, deptId=null, createTime=null, updateTime=null)
// System.out.println(emp);
// 起别名后的
// Emp emp1 = empMapper.getByIdTwo(4);
// Emp(id=4, username=weiyixiao, password=123456, name=韦一笑, gender=1, image=4.jpg, job=2, entrydate=2007-01-01, deptId=2, createTime=2024-05-04T15:36:06, updateTime=2024-05-04T15:36:06)
// System.out.println(emp1);
// 使用Results手动映射封装的
// Emp emp2 = empMapper.getByIdThree(4);
// // Emp(id=4, username=weiyixiao, password=123456, name=韦一笑, gender=1, image=4.jpg, job=2, entrydate=2007-01-01, deptId=2, createTime=2024-05-04T15:36:06, updateTime=2024-05-04T15:36:06)
// System.out.println(emp2);
// 配置完驼峰命名开关的
Emp emp3 = empMapper.getById(4);
// Emp(id=4, username=weiyixiao, password=123456, name=韦一笑, gender=1, image=4.jpg, job=2, entrydate=2007-01-01, deptId=null, createTime=null, updateTime=null)
System.out.println(emp3);
}
// 条件查询员工
@Test
public void testListSelect(){
List<Emp> emps = empMapper.list("张", (short) 1, LocalDate.of(2010, 1, 1), LocalDate.of(2020, 1, 1));
System.out.println(emps);
}
}
第二种方式(使用XML映射文件)
**Mapper代码,在src.main.java包下面右键 , 创建包使用com.jwz.mapper 这种.的格式 **
右键包名选择java,选择接口 , 名字起名叫 EmpMapper.java
package com.jwz.mapper;
import com.jwz.entity.Emp;
import org.apache.ibatis.annotations.*;
import java.time.LocalDate;
import java.util.List;
@Mapper
public interface EmpMapper {
public List<Emp> list(String name, Short gender, LocalDate begin, LocalDate end);
}
XML代码
- XML映射文件的名称与Mapper接口名称一致(Mapper名字叫userMapper则xml名字也要是这个名字),并且将XML映射文件和Mapper接口放置在相同包下(同包同名)(由于资源文件都是在resources文件夹下,比如我们mapper在com.jwz.mapper包下面,则我们也应该在resources下面也这样创建一个包,里面存放对应的xml文件)
- XML映射文件的namespace属性为Mapper接口全限定名一致。
- XML映射文件中sql语句的id与Mapper接口中的方法名一致,并保持返回类型一致。
resources下创建多级包使用com/jwz/mapper 这种/格式,不要用.
右键包名选择File , 名字和Mapper文件名对应 EmpMapper.xml
在这个网站下面可以找到XML的模版,预防更新先放个网站以后缺的时候来找,找到探究已映射的 SQL 语句下面这段就是模版代码
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"https://mybatis.org/dtd/mybatis-3-mapper.dtd">
<!--在接口的名字右键选择Copy/Paste Special 再选择 Copy Reference 这个就把接口的全限定名复制下来了,直接粘贴到namespace即可-->
<mapper namespace="com.jwz.mapper.EmpMapper">
<!-- 条件查询,id与mapper的方法名对应绑定,要保持一致 -->
<!--查询操作-->
<!-- resultType针对单条记录封装的实体类,代表返回的结果集类型 ,也是实体类的全限定名,复制方法和上面一样 -->
<select id="list" resultType="com.jwz.entity.Emp">
<!-- 这里面就是写sql语句的 -->
select * from emp
where name like concat('%',#{name},'%')
and gender = #{gender}
and entrydate between #{begin} and #{end}
order by update_time desc
</select>
</mapper>
测试代码
package com.jwz;
import com.jwz.entity.Emp;
import com.jwz.mapper.EmpMapper;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.util.List;
@SpringBootTest
class MyBatisEmpDemoApplicationTests {
@Autowired
private EmpMapper empMapper;
// 条件查询员工
@Test
public void testListSelect(){
List<Emp> emps = empMapper.list("张", (short) 1, LocalDate.of(2010, 1, 1), LocalDate.of(2020, 1, 1));
System.out.println(emps);
}
}
建议安装MybatisX插件,这样mapper对应的接口和xml对应的sql语句旁边都会有个小鸟,点击小鸟可以快速定位到sql或者mapper方法位置
还有个小技巧,安装完MybatisX插件后,写完mapper方法时,在方法名上面按Alt+enter选择Generate statement点击就会自动在对应的XML里面生成对应的标签和id值(标签的生成是根据方法名是否包含标签的关键字进行判断的)
日志输出
上面执行的sql语句默认没有打印出日志,如果我们想要看到日志信息怎么解决呢????
只需要在application.properties里面打开mybatis日志即可
mybatis.configuration.log-impl=org.apache.ibatis.logging.stdout.StdOutImpl
Mybatis动态SQL
- 随着用户的输入或外部条件的变化而变化的SQL语句,我们称为动态SQL
- 例如上面的条件查询,如果少传递参数就会有问题,但是实际开发中,有的需要名称查询,有的需要按照日期查询,这种参数会动态变化的就是动态查询
各标签作用
- < if >:用于判断条件是否成立。使用test属性进行条件判断,如果条件为true,则拼接SQL。
- < where >:where 元素只会在子元素有内容的情况下才插入where子句。而且会自动去除子句的开头的AND 或OR。
- 例如上面的添加和修改传递进来的都是员工对象,则所有的判断都指向对应的字段名即可,因为如果不传递该字段的话也是null
修改Mapper代码如下
package com.jwz.mapper;
import com.jwz.entity.Emp;
import org.apache.ibatis.annotations.*;
import java.time.LocalDate;
import java.util.List;
@Mapper
public interface EmpMapper {
// 修改员工
public int updateTest(Emp emp);
// 条件查询员工
public List<Emp> list(String name, Short gender, LocalDate begin, LocalDate end);
// 批量删除员工
public int deleteByIds(List<Integer> ids);
}
修改XML代码如下
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"https://mybatis.org/dtd/mybatis-3-mapper.dtd">
<!--在接口的名字右键选择Copy/Paste Special 再选择 Copy Reference 这个就把接口的全限定名复制下来了,直接粘贴到namespace即可-->
<mapper namespace="com.jwz.mapper.EmpMapper">
<!-- 条件查询,id与mapper的方法名对应绑定,要保持一致 -->
<!--查询操作-->
<!-- resultType针对单条记录封装的实体类,代表返回的结果集类型 ,也是实体类的全限定名,复制方法和上面一样 -->
<select id="list" resultType="com.jwz.entity.Emp">
<!-- 这里面就是写sql语句的 -->
<!-- where标签的作用就是根据传递来的参数动态判断应该拼接哪个SQL语句,如果都不满足条件,where关键字不会生成,如果只满足一个条件,比如只满足第二个条件,它会动态将前面的and关键字给去除,如果满足多个条件,从第二个条件开始不会过滤and关键字 -->
select * from emp
<where>
<if test="name != null">
name like concat('%',#{name},'%')
</if>
<if test="gender != null">
and gender = #{gender}
</if>
<if test="begin != null and end != null">
and entrydate between #{begin} and #{end}
</if>
order by update_time desc
</where>
</select>
<!--更新员工操作-->
<update id="updateTest">
update emp
<!-- 使用set标签,代替update语句中的set关键字 -->
<!-- 因为进行更新的时候,比如只更新username,其他字段未传递,那么生成的sql就会多出一个username后面的逗号,就会导致sql语句报错,set标签就可以根据参数动态判断是否应该添加后面逗号,不应该添加则会把逗号过滤掉 -->
<set>
<if test="username != null">
username=#{username},
</if>
<if test="name != null">
name=#{name},
</if>
<if test="gender != null">
gender=#{gender},
</if>
<if test="image != null">
image=#{image},
</if>
<if test="job != null">
job=#{job},
</if>
<if test="entrydate != null">
entrydate=#{entrydate},
</if>
<if test="deptId != null">
dept_id=#{deptId},
</if>
<if test="updateTime != null">
update_time=#{updateTime}
</if>
</set>
where id=#{id}
</update>
<!-- 批量删除员工数据 -->
<delete id="deleteByIds">
<!-- collection:要遍历的集合 , item:遍历出来的元素 , separator:分隔符 open:遍历开始前拼接的SQL片段 , close:遍历结束后拼接的SQL片段 -->
delete from emp where id in
<foreach collection="ids" item="id" separator="," open="(" close=")">
#{id}
</foreach>
</delete>
</mapper>
测试代码如下
package com.jwz;
import com.jwz.entity.Emp;
import com.jwz.mapper.EmpMapper;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.util.Arrays;
import java.util.List;
@SpringBootTest
class MyBatisEmpDemoApplicationTests {
@Autowired
private EmpMapper empMapper;
// 条件查询员工
@Test
public void testListSelect(){
List<Emp> emps = empMapper.list(null,(short) 1,null,null);
System.out.println(emps);
}
// 修改员工
// 修改员工信息
@Test
public void testUpdate(){
//要修改的员工信息
Emp emp = new Emp();
emp.setId(20);
emp.setUsername("songdaxia111");
//调用方法,修改员工数据
int i = empMapper.updateTest(emp);
if(i == 0){
System.out.println("修改失败");
}else{
System.out.println("修改成功,数据库影响了"+i+"行");
System.out.println("主键id为:"+emp.getId());
}
}
// 批量删除员工 - 13,14,15
@Test
public void testDeleteByIds(){
List<Integer> ids = Arrays.asList(13,14,15);
int i = empMapper.deleteByIds(ids);
if(i == 0){
System.out.println("批量删除失败");
}else{
System.out.println("批量删除成功,数据库影响了"+i+"行");
}
}
}
接下来的代码是对XML的一点改造,使用SQL和include标签将多余代码进行简化
- < sql >:定义可重用的 SQL 片段。
- < include >:通过属性refid,指定包含的sql片段。
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"https://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.jwz.mapper.EmpMapper">
<!-- sql标签用于将常用的sql语句片段封装起来以达到复用性,类似方法的封装 -->
<sql id="commonSelect">
select id, username, password, name, gender, image, job, entrydate, dept_id, create_time, update_time from emp
</sql>
<select id="list" resultType="com.jwz.mapper.EmpMapper">
<!-- include标签可以将sql封装的片段用于占位,相当于sql里面封装的sql语句被拿出来用了,这样做减少了重复性的代码,提高了代码的复用性 -->
<include refid="commonSelect"/>
<where>
<if test="name != null">
name like concat('%',#{name},'%')
</if>
<if test="gender != null">
and gender = #{gender}
</if>
<if test="begin != null and end != null">
and entrydate between #{begin} and #{end}
</if>
</where>
order by update_time desc
</select>
</mapper>
Slf4j日志打印技术
package com.jwz.controller;
import com.jwz.pojo.Result;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@Slf4j // 加上这个注解就可以使用log这个变量记录日志了
@RestController
public class DeptController {
@RequestMapping("/depts")
public void list(){
// 如果项目启动报错提示找不到log这个符号的话,使用以下方式解决
// 设置->构建、执行、部署->编译器->注解处理器->把右边的启用注解处理勾选上应用即可
log.info("查询数据"); // 这个控制台也会输出,日志也会同步打印记录
}
}
阶段性案例综合实战
环境搭建
- 准备数据库表(dept、emp)
- 创建springboot工程,引入对应的起步依赖(web、mybatis、mysql驱动、lombok)
- 配置文件application.properties中引入mybatis的配置信息,准备对应的实体类
- 准备对应的Mapper、Service(接口、实现类)、Controller基础结构
1. 数据库搭建
建表语句如下,我这里的数据库是user
-- 部门管理
create table dept(
id int unsigned primary key auto_increment comment '主键ID',
name varchar(10) not null unique comment '部门名称',
create_time datetime not null comment '创建时间',
update_time datetime not null comment '修改时间'
) comment '部门表';
insert into dept (id, name, create_time, update_time) values(1,'学工部',now(),now()),(2,'教研部',now(),now()),(3,'咨询部',now(),now()), (4,'就业部',now(),now()),(5,'人事部',now(),now());
-- 员工管理(带约束)
create table emp (
id int unsigned primary key auto_increment comment 'ID',
username varchar(20) not null unique comment '用户名',
password varchar(32) default '123456' comment '密码',
name varchar(10) not null comment '姓名',
gender tinyint unsigned not null comment '性别, 说明: 1 男, 2 女',
image varchar(300) comment '图像',
job tinyint unsigned comment '职位, 说明: 1 班主任,2 讲师, 3 学工主管, 4 教研主管, 5 咨询师',
entrydate date comment '入职时间',
dept_id int unsigned comment '部门ID',
create_time datetime not null comment '创建时间',
update_time datetime not null comment '修改时间'
) comment '员工表';
INSERT INTO emp
(id, username, password, name, gender, image, job, entrydate,dept_id, create_time, update_time) VALUES
(1,'jinyong','123456','金庸',1,'1.jpg',4,'2000-01-01',2,now(),now()),
(2,'zhangwuji','123456','张无忌',1,'2.jpg',2,'2015-01-01',2,now(),now()),
(3,'yangxiao','123456','杨逍',1,'3.jpg',2,'2008-05-01',2,now(),now()),
(4,'weiyixiao','123456','韦一笑',1,'4.jpg',2,'2007-01-01',2,now(),now()),
(5,'changyuchun','123456','常遇春',1,'5.jpg',2,'2012-12-05',2,now(),now()),
(6,'xiaozhao','123456','小昭',2,'6.jpg',3,'2013-09-05',1,now(),now()),
(7,'jixiaofu','123456','纪晓芙',2,'7.jpg',1,'2005-08-01',1,now(),now()),
(8,'zhouzhiruo','123456','周芷若',2,'8.jpg',1,'2014-11-09',1,now(),now()),
(9,'dingminjun','123456','丁敏君',2,'9.jpg',1,'2011-03-11',1,now(),now()),
(10,'zhaomin','123456','赵敏',2,'10.jpg',1,'2013-09-05',1,now(),now()),
(11,'luzhangke','123456','鹿杖客',1,'11.jpg',5,'2007-02-01',3,now(),now()),
(12,'hebiweng','123456','鹤笔翁',1,'12.jpg',5,'2008-08-18',3,now(),now()),
(13,'fangdongbai','123456','方东白',1,'13.jpg',5,'2012-11-01',3,now(),now()),
(14,'zhangsanfeng','123456','张三丰',1,'14.jpg',2,'2002-08-01',2,now(),now()),
(15,'yulianzhou','123456','俞莲舟',1,'15.jpg',2,'2011-05-01',2,now(),now()),
(16,'songyuanqiao','123456','宋远桥',1,'16.jpg',2,'2007-01-01',2,now(),now()),
(17,'chenyouliang','123456','陈友谅',1,'17.jpg',NULL,'2015-03-21',NULL,now(),now());
2.创建SpringBoot项目
新建项目 -> (项目名,语言:Java,类型:Maven,其他不用动不用改,可以改下包名为com.jwz不要第三个) -> 下一步 -> (展开web选择Spring Web 展开SQL选择MyBatis Framework和MySQL Driver) -> 创建
删除多余文件(.idea , .gitignore , HELP.md , mvnw , mvnw.cmd)
在项目的pom.xml文件加入lombok的依赖,并点击右上角刷新下载一下
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</dependency>
数据库语法提示配过的不用配置了,但是在idea连接数据库还是要连接一下的,每次打开项目都要重新连接一下,否则会断开数据库了,点击会跳转到连接数据库的步骤位置
3.在src/main/resources/application.properties加入以下配置信息
# 驱动类名称
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
# 数据库连接的url,最后一个单词是数据库名称
spring.datasource.url=jdbc:mysql://localhost:3306/user
# 连接数据库的用户名
spring.datasource.username=root
# 连接数据库的密码
spring.datasource.password=admin
# 配置Mybatis的Mysql的日志信息打印
mybatis.configuration.log-impl=org.apache.ibatis.logging.stdout.StdOutImpl
# 打开Mybatis的驼峰命名检测开关
mybatis.configuration.map-underscore-to-camel-case=true
4.搭建以下目录结构
5. 三层架构各部分文件的代码内容
pojo层代码
部门(Dept)
package com.jwz.pojo;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.time.LocalDateTime;
/**
* 部门实体类
*/
@Data
@NoArgsConstructor
@AllArgsConstructor
public class Dept {
private Integer id; //ID
private String name; //部门名称
private LocalDateTime createTime; //创建时间
private LocalDateTime updateTime; //修改时间
}
员工(Emp)
package com.jwz.pojo;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.time.LocalDate;
import java.time.LocalDateTime;
/**
* 员工实体类
*/
@Data
@NoArgsConstructor
@AllArgsConstructor
public class Emp {
private Integer id; //ID
private String username; //用户名
private String password; //密码
private String name; //姓名
private Short gender; //性别 , 1 男, 2 女
private String image; //图像url
private Short job; //职位 , 1 班主任 , 2 讲师 , 3 学工主管 , 4 教研主管 , 5 咨询师
private LocalDate entrydate; //入职日期
private Integer deptId; //部门ID
private LocalDateTime createTime; //创建时间
private LocalDateTime updateTime; //修改时间
}
工具类(Result:封装了统一响应结果)
package com.jwz.pojo;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
@Data
@NoArgsConstructor
@AllArgsConstructor
public class Result {
private Integer code;//响应码,1 代表成功; 0 代表失败
private String msg; //响应信息 描述字符串
private Object data; //返回的数据
//增删改 成功响应
public static Result success(){
return new Result(1,"success",null);
}
//查询 成功响应
public static Result success(Object data){
return new Result(1,"success",data);
}
//失败响应
public static Result error(String msg){
return new Result(0,msg,null);
}
}
分页封装类:PageBean
package com.jwz.pojo;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.util.List;
/**
* 分页查询结果封装类
*/
@Data
@NoArgsConstructor
@AllArgsConstructor
public class PageBean {
private Long total; // 总记录数
private List rows; // 数据列表
}
mapper层代码
部门(DeptMapper)
package com.jwz.mapper;
import com.jwz.pojo.Dept;
import org.apache.ibatis.annotations.Delete;
import org.apache.ibatis.annotations.Insert;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Select;
import java.util.List;
/**
* 部门管理
*/
@Mapper
public interface DeptMapper {
/**
* 查询全部部门数据
* @return
*/
@Select("select * from dept")
List<Dept> list();
/**
* 根据id删除部门
* @param id
* @return
*/
@Delete("delete from dept where id = #{id}")
int delete(Integer id);
/**
* 新增员工
* @param dept
* @return
*/
@Insert("insert into dept(name, create_time, update_time) value (#{name},#{createTime},#{updateTime})")
int add(Dept dept);
}
员工(EmpMapper)
package com.jwz.mapper;
import com.jwz.pojo.Emp;
import org.apache.ibatis.annotations.Insert;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Select;
import java.time.LocalDate;
import java.util.List;
/**
* 员工管理
*/
@Mapper
public interface EmpMapper {
// 获取总记录数
@Select("select count(*) from emp")
public Long count();
// 查询分页的记录
@Select("select * from emp limit #{start},#{pageSize}")
public List<Emp> page(Integer start, Integer pageSize);
// 条件查询并含有分页的记录
// 这里使用XML的动态映射去写
// 在resources下新建com/jwz/mapper/EmpMapper.xml
public List<Emp> pageTwo(Integer start, Integer pageSize, String name, Short gender, LocalDate begin, LocalDate end);
// 批量删除员工
int delete(List<Integer> ids);
// 新增员工
@Insert("insert into emp(username, name, gender, image, job, entrydate, dept_id, create_time, update_time) values (#{username},#{name},#{gender},#{image},#{job},#{entrydate},#{deptId},#{createTime},#{updateTime})")
void insert(Emp emp);
}
service层代码
部门(DeptService)
package com.jwz.service;
import com.jwz.pojo.Dept;
import java.util.List;
/**
* 部门管理
*/
public interface DeptService {
/**
* 查询全部部门数据
* @return
*/
List<Dept> list();
/**
* 根据id删除部门
* @param id
* @return
*/
int delete(Integer id);
/**
* 修改员工
* @param dept
* @return
*/
int add(Dept dept);
}
员工(EmpService)
package com.jwz.service;
import com.jwz.pojo.Emp;
import com.jwz.pojo.PageBean;
import org.springframework.format.annotation.DateTimeFormat;
import java.time.LocalDate;
import java.util.List;
/**
* 员工管理
*/
public interface EmpService {
/**
* 实现分页查询
* @param page
* @param pageSize
* @return
*/
PageBean page(Integer page, Integer pageSize);
/**
* 条件分页查询
* @param page
* @param pageSize
* @param name
* @param gender
* @param begin
* @param end
* @return
*/
PageBean pageTwo(Integer page, Integer pageSize, String name, Short gender, LocalDate begin, LocalDate end);
/**
* 批量删除员工
* @param ids
* @return
*/
int delete(List<Integer> ids);
/**
* 新增员工
* @param emp
*/
void save(Emp emp);
}
ServiceImpl层代码
部门(DeptServiceImpl)
package com.jwz.service.impl;
import com.jwz.mapper.DeptMapper;
import com.jwz.pojo.Dept;
import com.jwz.service.DeptService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.time.LocalDateTime;
import java.util.List;
@Service // 将实现类放入bean容器内
public class DeptServiceImpl implements DeptService {
// 自动注入mapper接口
@Autowired
private DeptMapper deptMapper;
// 查询部门
@Override
public List<Dept> list() {
return deptMapper.list();
}
// 根据id删除部门
@Override
public int delete(Integer id) {
return deptMapper.delete(id);
}
// 修改员工
@Override
public int add(Dept dept) {
dept.setCreateTime(LocalDateTime.now());
dept.setUpdateTime(LocalDateTime.now());
return deptMapper.add(dept);
}
}
员工(EmpServiceImpl)
package com.jwz.service.impl;
import com.jwz.mapper.EmpMapper;
import com.jwz.pojo.Emp;
import com.jwz.pojo.PageBean;
import com.jwz.service.EmpService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.util.List;
@Service
public class EmpServiceImpl implements EmpService {
@Autowired
private EmpMapper empMapper;
/**
* 分页查询(这段代码可以使用pageHelper简化,但是个人没感觉简化多少,就没写,有兴趣的可以自行百度这个插件)
* @param page
* @param pageSize
* @return
*/
@Override
public PageBean page(Integer page, Integer pageSize) {
// 获取总记录数
Long count = empMapper.count();
// 获取分页查询的结果列表
List<Emp> page1 = empMapper.page((page - 1) * pageSize, pageSize);
// 封装PageBean对象
PageBean pageBean = new PageBean(count, page1);
return pageBean;
}
/**
* 条件分页查询
* @param page
* @param pageSize
* @param name
* @param gender
* @param begin
* @param end
* @return
*/
@Override
public PageBean pageTwo(Integer page, Integer pageSize, String name, Short gender, LocalDate begin, LocalDate end) {
// 获取总记录数
Long count = empMapper.count();
// 获取分页查询的结果列表
List<Emp> page1 = empMapper.pageTwo((page - 1) * pageSize, pageSize,name,gender,begin,end);
// 封装PageBean对象
PageBean pageBean = new PageBean(count, page1);
return pageBean;
}
/**
* 批量删除员工
* @param ids
* @return
*/
@Override
public int delete(List<Integer> ids) {
return empMapper.delete(ids);
}
/**
* 新增员工
* @param emp
*/
@Override
public void save(Emp emp) {
// 设置创建日期和更新日期
emp.setCreateTime(LocalDateTime.now());
emp.setUpdateTime(LocalDateTime.now());
// 调用mapper方法
empMapper.insert(emp);
}
}
Controller层代码
部门(DeptController)
package com.jwz.controller;
import com.jwz.pojo.Dept;
import com.jwz.pojo.Result;
import com.jwz.service.DeptService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import java.util.List;
/**
* 部门管理
*/
// 声明日志记录对象,用于记录日志信息
@Slf4j // 加上这个注解就可以使用log这个变量记录日志了
@RestController
@RequestMapping("/depts") // 将所有请求的公共部分抽取到类上了
public class DeptController {
// 自动注入service层
@Autowired
private DeptService deptService;
// 部门管理
// 查询部门(get请求:http://localhost:8080/depts)
// (下面两种方式效果相同,都是路径为'/dept',请求方式为GET)
// @RequestMapping(value = "/depts",method = RequestMethod.GET)
@GetMapping
public Result list() {
// 如果项目启动报错提示找不到log这个符号的话,使用以下方式解决
// 设置->构建、执行、部署->编译器->注解处理器->把右边的启用注解处理勾选上应用即可
log.info("查询全部部门数据");
// 调用service层查询部门数据
List<Dept> deptList = deptService.list();
return Result.success(deptList);
}
// 删除部门(delete请求:http://localhost:8080/depts/1)
@DeleteMapping("/{id}")
public Result delete(@PathVariable("id") Integer id){
log.info("根据id删除部门:{}",id);
// 调用service删除部门
int i = deptService.delete(id);
if(i == 0){
log.info("删除失败");
return Result.error("删除失败");
}else{
log.info("删除成功");
return Result.success();
}
}
// 新增部门(post请求:http://localhost:8080/depts,body的json里面存放参数{"name":"萧寂"})
@PostMapping
public Result add(@RequestBody Dept dept){
int i = deptService.add(dept);
if(i == 0){
log.info("新增失败");
return Result.error("新增失败");
}else{
log.info("新增成功");
return Result.success();
}
}
}
员工(EmpController)
package com.jwz.controller;
import com.jwz.pojo.Emp;
import com.jwz.pojo.PageBean;
import com.jwz.pojo.Result;
import com.jwz.service.EmpService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.format.annotation.DateTimeFormat;
import org.springframework.web.bind.annotation.*;
import java.time.LocalDate;
import java.util.List;
/**
* 员工管理
*/
@Slf4j
@RequestMapping("/emps")
@RestController
public class EmpController {
@Autowired
private EmpService empService;
// 分页查询(get请求:http://localhost:8080/emp?page=2&pageSize=2)
@GetMapping("/sel")
public Result page(@RequestParam(defaultValue = "1") Integer page,@RequestParam(defaultValue = "10") Integer pageSize){
log.info("分页查询,参数:{},{},不传递默认为1,10",page,pageSize);
// 调用分页查询
PageBean pageBean = empService.page(page,pageSize);
return Result.success(pageBean);
}
// 条件分页查询((get请求:http://localhost:8080/emps?page=2&pageSize=2&name=张&gender=1))
@GetMapping
public Result pageTwo(@RequestParam(defaultValue = "1") Integer page, @RequestParam(defaultValue = "10") Integer pageSize, String name, Short gender, @DateTimeFormat(pattern = "yyyy-MM-dd") LocalDate begin,@DateTimeFormat(pattern = "yyyy-MM-dd") LocalDate end){
log.info("分页查询,参数:{},{},{},{},{},{} 不传递默认页码和数量默认为1,10",page,pageSize,name,gender,begin,end);
// 调用分页查询
PageBean pageBean = empService.pageTwo(page,pageSize,name,gender,begin,end);
return Result.success(pageBean);
}
// 批量删除(delete请求:http://localhost:8080/emps/13,14,15)
@DeleteMapping("/{ids}")
public Result deletes(@PathVariable List<Integer> ids){
log.info("批量删除操作,ids",ids);
int i = empService.delete(ids);
if(i == 0){
log.info("批量删除失败");
return Result.error("批量删除失败");
}else{
log.info("批量删除成功");
return Result.success("批量删除成功");
}
}
// 新增员工
// post请求(http://localhost:8080/emps)
// body的json请求参数为{
// "image":"123",
// "username":"linpingzhi",
// "name":"林平之",
// "gender":1,
// "job":1,
// "entrydate":"2015-09-08",
// "deptId":1
// }
@PostMapping
public Result save(@RequestBody Emp emp){
log.info("新增员工",emp);
empService.save(emp);
return Result.success();
}
}
com/jwz/mapper/EmpMapper.xml(员工管理有分页需求)
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"https://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.jwz.mapper.EmpMapper">
<!-- 条件查询员工 -->
<select id="pageTwo" resultType="com.jwz.pojo.Emp">
select * from emp
<where>
<if test="name != null and name != ''">
name like concat('%' , #{name} , '%')
</if>
<if test="gender != null">
and gender = #{gender}
</if>
<if test="begin != null and end !=null">
and entrydate between #{begin} and #{end}
</if>
</where>
order by update_time desc
</select>
<!-- 批量删除员工 -->
<delete id="delete">
delete from emp where id in
<foreach collection="ids" item="id" separator="," open="(" close=")">
#{id}
</foreach>
</delete>
</mapper>
文件上传(oss)
步骤:
- 1.登录阿里云云计算官网
- 2.点击右上角控制台
- 3.鼠标悬浮左上角的三条杠上面会出现一个弹窗
- 4.在弹窗内搜索关键词oss
- 5.点击基础存储服务->对象存储oss(如果没开通的话会提示开通一下,按照提示开通就好)
- 6.新页面的概览右下角有购买,建议买一下,五块钱就6个月时长
- 7.点击Bucket列表->新建Bucket列表->创建Bucket->输入名称->读写权限改为公共读->点击完成创建即可,其他不用修改
- 8.鼠标悬浮到右上角头像->AccessKey管理->没有的话点击创建AccessKey(创建完成会生成AccessKey ID 和 AccessKey Secret)这两个就是相当于账号,如果输入别人的AccessKey ID 和 AccessKey Secret则图片就被传到别人的仓库了
- 9.有了AccessKey ID 和 AccessKey Secret和Bucket后就可以做项目了
- 10.返回到创建Bucket那个页面,下拉左侧列表找到SDK下载,点击进去
- 11.点击Java图标旁边的文档icon,在弹出框点击文档中心打开
- 12.在文档页面的开发参考 -> SDK参考 -> Java -> 安装 (在这个页面里面找到要安装的pom.xml依赖代码,找不到也没事,下面具体操作代码我也会粘贴到文档内)
- 13.在文档页面的开发参考 -> SDK参考 -> Java -> 对象/文件 -> 上传文件 -> 简单上传 -> 将看到的demo代码粘贴一下
所有用到的
1.pom.xml文件加入以下代码
<dependency>
<groupId>com.aliyun.oss</groupId>
<artifactId>aliyun-sdk-oss</artifactId>
<version>3.15.1</version>
</dependency>
<dependency>
<groupId>javax.xml.bind</groupId>
<artifactId>jaxb-api</artifactId>
<version>2.3.1</version>
</dependency>
<dependency>
<groupId>javax.activation</groupId>
<artifactId>activation</artifactId>
<version>1.1.1</version>
</dependency>
<!-- no more than 2.3.3-->
<dependency>
<groupId>org.glassfish.jaxb</groupId>
<artifactId>jaxb-runtime</artifactId>
<version>2.3.3</version>
</dependency>
别忘了右上角点击maven刷新下载一下
2.测试类替换以下代码,都是从官网粘贴的demo(目前官方demo没有设置密钥的,好像是配置到环境变量是从环境变量读取了,这里我还是在代码里面设置,下面加了点微改),只需要关心我写注释的地方即可
package com.jwz.service.impl;
import com.aliyun.oss.ClientException;
import com.aliyun.oss.OSS;
import com.aliyun.oss.common.auth.*;
import com.aliyun.oss.OSSClientBuilder;
import com.aliyun.oss.OSSException;
import com.aliyun.oss.model.PutObjectRequest;
import com.aliyun.oss.model.PutObjectResult;
import java.io.File;
public class Demo {
public static void main(String[] args) throws Exception {
// 找到上面创建Bucket的页面,找到Bucket列表,点击需要上传的Bucket,点击概览,往下拉找到访问端口,找到外网访问的地址替换掉下面的地址,只替换https协议后面的
String endpoint = "https://oss-cn-beijing.aliyuncs.com";
// AccessKey
String accessKeyId = "LTAI5tKQp68gcpVR6tHmkvgL";
// AccessKey Secret
String accessKeySecret = "CwIVN2QyGOcnsgJKAVoakwmmBeJRmC";
// 填写需要上传到某一Bucket的Bucket的名称
String bucketName = "testsxj";
// 填写上传的文件名称(不要包含Bucket名称)
String objectName = "1.jpg";
// 填写本地文件的完整路径,例如C:\\Users\\22560\\Desktop\\danzi\\保存复制图片和生成二维码\\src\\assets\\logo.png
// 如果未指定本地路径,则默认从示例程序所属项目对应本地路径中上传文件。
String filePath= "C:\\Users\\22560\\Desktop\\danzi\\保存复制图片和生成二维码\\src\\assets\\logo.png";
OSS ossClient = new OSSClientBuilder().build(endpoint, accessKeyId,accessKeySecret);
try {
PutObjectRequest putObjectRequest = new PutObjectRequest(bucketName, objectName, new File(filePath));
PutObjectResult result = ossClient.putObject(putObjectRequest);
} catch (OSSException oe) {
System.out.println("Caught an OSSException, which means your request made it to OSS, "
+ "but was rejected with an error response for some reason.");
System.out.println("Error Message:" + oe.getErrorMessage());
System.out.println("Error Code:" + oe.getErrorCode());
System.out.println("Request ID:" + oe.getRequestId());
System.out.println("Host ID:" + oe.getHostId());
} catch (ClientException ce) {
System.out.println("Caught an ClientException, which means the client encountered "
+ "a serious internal problem while trying to communicate with OSS, "
+ "such as not being able to access the network.");
System.out.println("Error Message:" + ce.getMessage());
} finally {
if (ossClient != null) {
ossClient.shutdown();
}
}
}
}
但是上面的官方demo有点缺陷就是我们上传的是固定路径的图片,并且上传完成后也没有返回图片的路径,下面提供一个阿里云oss的工具包,上传成功后返回的有url路径地址,供前端使用
由于这个工具类要在controller类使用,但是这个工具类不属于三层架构,则仅仅需要加@Component注解即可,这样的话在controller可以动态调用,因为被加入到容器里面了
package com.jwz.controller;
import com.aliyun.oss.OSS;
import com.aliyun.oss.OSSClientBuilder;
import org.springframework.stereotype.Component;
import org.springframework.web.multipart.MultipartFile;
import java.io.*;
import java.util.UUID;
/**
* 阿里云 OSS 工具类
*/
@Component
public class AliOSSUtils {
// 找到上面创建Bucket的页面,找到Bucket列表,点击需要上传的Bucket,点击概览,往下拉找到访问端口,找到外网访问的地址替换掉下面的地址,只替换https协议后面的
private String endpoint = "https://oss-cn-beijing.aliyuncs.com";
private String accessKeyId = "yourAccessKey"; // AccessKey
private String accessKeySecret = "AccessKey Secret"; // AccessKey Secret
// 填写需要上传到某一Bucket的Bucket的名称
private String bucketName = "testsxj";
/**
* 实现上传图片到OSS
*/
public String upload(MultipartFile file) throws IOException {
// 获取上传的文件的输入流
InputStream inputStream = file.getInputStream();
// 避免文件覆盖
String originalFilename = file.getOriginalFilename();
String fileName = UUID.randomUUID().toString() + originalFilename.substring(originalFilename.lastIndexOf("."));
//上传文件到 OSS
OSS ossClient = new OSSClientBuilder().build(endpoint, accessKeyId, accessKeySecret);
ossClient.putObject(bucketName, fileName, inputStream);
//文件访问路径
String url = endpoint.split("//")[0] + "//" + bucketName + "." + endpoint.split("//")[1] + "/" + fileName;
// 关闭ossClient
ossClient.shutdown();
return url;// 把上传到oss的路径返回
}
}
上面工具类的使用方式如下
package com.jwz.controller;
import com.jwz.pojo.Result;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.multipart.MultipartFile;
import java.io.IOException;
@RestController
public class OssController {
@Autowired
private AliOSSUtils aliOSSUtils;
@PostMapping("/upload")
public Result upload(@RequestParam("image") MultipartFile image) throws IOException {
System.out.println("image"+image.getOriginalFilename());
String url = aliOSSUtils.upload(image);
return Result.success(url);
}
}
参数配置化
上面的代码可以稍加调整,可以看到整个项目中只需要用到一次AccessKey和AccessKey Secret , 但是配置文件也是项目只加载一次 , 将上面的秘钥信息存入application.properties里面,新增加入以下代码
#阿里云OSS配置
aliyun.oss.endpoint=https://oss-cn-hangzhou.aliyuncs.com
aliyun.oss.accessKeyId=LTAI4GCH1vX6DKqJWxd6nEuW
aliyun.oss.accessKeySecret=yBshYweHOpqDuhCArrVHwIiBKpyqSL
aliyun.oss.bucketName=web-tlias
然后修改oss工具类
package com.jwz.controller;
import com.aliyun.oss.OSS;
import com.aliyun.oss.OSSClientBuilder;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
import org.springframework.web.multipart.MultipartFile;
import java.io.IOException;
import java.io.InputStream;
import java.util.UUID;
/**
* 阿里云 OSS 工具类
*/
@Component
public class AliOSSUtils {
// 通过spring提供的@Value注解读取到配置文件的信息,将键作为参数读取出来的值赋值给下面的变量
@Value("${aliyun.oss.endpoint}")
private String endpoint;
@Value("${aliyun.oss.accessKeyId}")
private String accessKeyId;
@Value("${aliyun.oss.accessKeySecret}")
private String accessKeySecret;
@Value("${aliyun.oss.bucketName}")
private String bucketName;
/**
* 实现上传图片到OSS
*/
public String upload(MultipartFile file) throws IOException {
// 获取上传的文件的输入流
InputStream inputStream = file.getInputStream();
// 避免文件覆盖
String originalFilename = file.getOriginalFilename();
String fileName = UUID.randomUUID().toString() + originalFilename.substring(originalFilename.lastIndexOf("."));
//上传文件到 OSS
OSS ossClient = new OSSClientBuilder().build(endpoint, accessKeyId, accessKeySecret);
ossClient.putObject(bucketName, fileName, inputStream);
//文件访问路径
String url = endpoint.split("//")[0] + "//" + bucketName + "." + endpoint.split("//")[1] + "/" + fileName;
// 关闭ossClient
ossClient.shutdown();
return url;// 把上传到oss的路径返回
}
}
配置文件application.yaml
后缀名可以是yml或者yaml(这两个后缀是同一个文件)
配置文件直接放到application.properties同级目录下
如我们平时在application.properties里面配置信息都是如下结构
server.port=8080
server.address:127.0.0.1
aliyun.oss.endpoint=https://oss-cn-beijing.aliyuncs.com
aliyun.oss.bucketName=demobucker
在application.yaml也可以说是在application.yml后缀的文件内写法如下
# 值前面要有空格,否则不生效
server:
port: 8080
address: 127.0.0.1
aliyun:
oss:
endpoint: https://oss-cn-beijing.aliyuncs.com
bucketName: demobucker
简化了共有部分的代码
使用application.yaml配置文件注意事项
- 大小写敏感
- 数值前边必须有空格,作为分隔符
- 使用缩进表示层级关系,缩进时,不允许使用Tab键,只能用空格(idea中会自动将Tab转换为空格)
- 缩进的空格数目不重要,只要相同层级的元素左侧对齐即可
- #表示注释,从这个字符一直到行尾,都会被解析器忽略
application.yaml文件定义对象/Map集合和定义集合List/Set
# 定义对象/Map集合
user:
name: Tom
age: 20
address: beijing
# 定义集合List/Set
hobby:
- java
- c
- game
- sport
@ConfigurationProperties注解
例如我们application.yaml文件是以下内容
aliyun:
oss:
endpoint: https://oss-cn-beijing.aliyuncs.com
bucketName: demobucker
我们需要用@ConfigurationProperties将值注入到bean对象
package com.jwz.controller;
import lombok.Data;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.stereotype.Component;
@Data
@Component
@ConfigurationProperties(prefix = "aliyun.oss")
public class Demo {
private String endpoint;
private String bucketName;
}
在其他页面读取值
package com.jwz.controller;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
public class aaa {
@Autowired
private Demo demo;
@GetMapping("/")
public void test(){
String endpoint = demo.getEndpoint();
String bucketName = demo.getBucketName();
System.out.println(endpoint+"---"+bucketName);
// 浏览器访问localhost:8080 查看控制台得到 https://oss-cn-beijing.aliyuncs.com---demobucker
}
}
上面的原理就是相当于把application.yaml文件内的数据读取到了实体类,实体类的参数和application.yaml里面的键保持一致,并将其注入为bean对象,其他页面需要用到直接自动注入进来就可以了,调用实体类的get方法即可获取