【参考视频】https://www.bilibili.com/video/BV1m84y1w7Tb?p=167&vd_source=38a16daddd38b4b4d4536e9c389e197f
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=18System.out.println(simplePojo); // simplePojo{name = 萧寂, age = 18}// 访问如下地址: http://localhost:8080/simplePojo?age=18// 不传哪个哪个就为nullSystem.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:25System.out.println(updateTime); // 2024-04-27T10:00:25return "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;}@Overridepublic 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/1234System.out.println(id+":"+preId); // 1:1234return "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{@Overridepublic 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();@Overridepublic 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{@Overridepublic 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; // 类型是接口的类型(多态写法)@Overridepublic String serviceA(Integer num) {// 这里用于对数据进行业务的处理// 例如,调用daoImpl里面的方法,拿到初始化访问到的数据Integer i = dao.daoA(num); // 1234int 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; // 类型是接口的类型(多态写法)@Overridepublic String serviceA(Integer num) {// 这里用于对数据进行业务的处理// 例如,调用daoImpl里面的方法,拿到初始化访问到的数据Integer i = dao.daoA(num); // 1234int 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 表名;