目录
<<回到导览
Spring boot
简介:Spring Boot 基于Spring,简化了配置,降低的入门难度,可以帮助我们非常快速的构建应用程序、简化开发、提高效率
需求:使用 SpringBoot 开发一个web应用,浏览器发起请求 /hello后,给浏览器返回字符串 "Hello World ~"
-
创建spring boot项目(保证网络间接正常)
-
删除一些暂时不用的文件
-
在包下创建文件
-
编写这个文件
java// 请求处理类 @RestController public class HelloController { // 表名这个请求处理类,处理的是"/hello" @RequestMapping("/hello") public String Hello() { System.out.println("Hello World"); return "Hello World!!!"; } }
运行启动类(SpringDemoApplication)
-
访问服务
访问
http://localhost:8080/hello
或者http://127.0.0.1:8080/hello
每访问一次这个服务,控制台还会打印一次Hello World
1. http协议
概念:Hyper Text Transfer Protocol, 超文本传输协议,规定了浏览器和服务器之间数据传输的规则。
特点:
- 基于TCP协议:面向连接,安全
- 基于请求-响应模型的:一次请求对应一次响应
- HTTP协议是++无状态++ 的协议:对于事务处理没有记忆能力。每次请求-响应都是独立的。
- 缺点:多次请求间不能共享数据。
- 优点:速度快
1.1.请求协议
请求方式 | 请求参数位置 | 请求大小 |
---|---|---|
GET | 在请求行(没有请求体) | 有大小限制 |
POST | 在请求体 | 没有大小限制 |
-
GET请求
-
POST请求
1.2.响应协议
响应协议和POST请求有些相似,分为响应行、响应头、响应体,响应数据放在响应体里面

状态码 | 说明 |
---|---|
1xx | 临时状态码,表示请求已经接收,应该继续请求或者如果它已经完成则忽略它。 |
2xx | 成功接收,处理已完成。 |
3xx | 重定向到其他地方;让客户端再发起一次请求以完成整个处理。 |
4xx | 客户端错误,责任在客户端。(如:请求了不存在的资源、客户端未被授权、禁止访问等。) |
5xx | 服务器错误,责任在服务端。(如:程序抛出异常等)。 |
常用状态码 | 解释 |
---|---|
200 | 处理成功 |
302/304 | location重定向/隐式重定向 |
400 | 客户端语法错误 |
403 | 服务器拒绝提供服务(没有权限) |
404 | 请求资源不存在(url错误) |
405 | 请求方式有误 |
500 | 服务器发生不可预期的错误 |
503 | 服务器尚未准备好处理请求 |
2.Tomcat
Web服务器是一个软件程序,对HTTP协议的操作进行封装,简化web服务器开发
作用:部署web项目,对外提供网上信息浏览服务
Tomcat:一个轻量级的web服务器,支持servlet、jsp等少量avaEE规范。也被称为web容器、servlet容器。
起步依赖:利用maven中依赖传递的特性,把开发某一个功能常见的依赖整合在一起(如web)

在spring boot web开发环境中,已经集成了Tomcat

2.1.请求
2.1.1.apifox
apifox官网:https://app.apifox.com/
apifox使用教程:https://www.bilibili.com/video/BV1Jc41147xC
在使用apifox之前要安装插件Apifox Browser Extension
:

尝试用apifox测试接口

2.1.2.简单参数
简单参数:参数名和变量名相同,定义形参即可接收参数
java
@RestController
public class RequestController {
@RequestMapping("/simpleParam")
public String simpleParam(String name, int age) {
System.out.println(name + ":" + age);
return "OK";
}
}

如果方法形参名称与请求参数名称不匹配,不能接收值,但是不会报错
这时,可以使用@RequestParam
完成映射,但是该注解的required属性默认是true,代表++请求参数必须传递++
java
@RestController
public class RequestController {
@RequestMapping("/simpleParam")
public String simpleParam(@RequestParam(name = "name") String username, int age) {
System.out.println(username + ":" + age);
return "OK";
}
}
2.1.3.实体参数
实体参数:多个参数名和形参变量名相同,定义POJO接收即可
java
@RestController
public class RequestController {
@RequestMapping("/simplePojo")
public String simpleParam(User user) {
System.out.println(user);
return "OK";
}
}
java
public class User{
private String name;
private int age;
// Getter、Setter、toString
}

-
示例
为上面用户添加地址信息(包含省份和城市)
java@RestController public class RequestController { @RequestMapping("/complexPojo") public String complexPojo(User user) { System.out.println(user); return "OK"; } }
javapublic class User{ private String name; private int age; private Address address; // Getter、Setter、toString }
javapublic class Address { private String province; private String city; // Getter、Setter、toString }
2.1.4.数组集合参数
-
数组参数:请求参数名与形参数组名称相同,定义数组类型形参即可接收参数
java@RestController public class RequestController { @RequestMapping("/arrayParam") public String arrayParam(String[] hobby) { System.out.println(Arrays.toString(hobby)); return "OK"; } }
-
集合参数 :请求参数名与形参集合名称相同,通过
@RequestParam
绑定参数关系java@RestController public class RequestController { @RequestMapping("/listParam") public String listParam(@RequestParam List<String> hobby) { System.out.println(hobby); return "OK"; } }
2.1.5.日期参数
日期参数:使用@DateTimeFormat注解完成日期参数格式的转换
java
@RestController
public class RequestController {
@RequestMapping("/dateParam")
public String dateParam(@DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")LocalDateTime updateTime) {
System.out.println(updateTime);
return "OK";
}
}

2.1.6.(重点)JSON参数
JSON参数:JSON数据键名和形参属性名相同,定义POJO类型形参即可接收参数,需要使用@RequestBody
标识
在上面的请求中,都是用的GET请求方式,++请求参数在请求行++ ,但利用json字符串传参要用POST请求方式,++请求参数在请求体++
-
例如:
json{ "name":"Tom", "age":18, "address":{ "province":"四川", "city":"成都" } }
-
json参数传递
java@RestController public class RequestController { @RequestMapping("/jsonParam") public String jsonParam(@RequestBody User user) { System.out.println(user); return "OK"; } }
2.1.7.路径参数
路径参数:通过URL直接传递参数,使用{}
来标识该路径参数,需要使用@RequestMapping
获取路径参数
java
@RestController
public class RequestController {
@RequestMapping("/pathParam/{id}")
public String pathParam(@PathVariable Integer id) {
System.out.println(id);
return "OK";
}
}

-
传递多个路径参数
java@RestController public class RequestController { @RequestMapping("/pathParam/{id}/{uid}") public String pathParam(@PathVariable Integer id, @PathVariable Integer uid) { System.out.println(id + "," + uid); return "OK"; } }
2.2.响应
@RestController
注解包含了++@ResponseBody++ 注解++@Controller注解++
-
统一响应结果:
- 响应码
- 提示信息
- 返回的数据
java// Result public class Result { private Integer code ;//1 成功 , 0 失败 private String msg; //提示信息 private Object data; //数据 data public Result() { } public Result(Integer code, String msg, Object data) { this.code = code; this.msg = msg; this.data = data; } public Integer getCode() { return code; } public void setCode(Integer code) { this.code = code; } public String getMsg() { return msg; } public void setMsg(String msg) { this.msg = msg; } public Object getData() { return data; } public void setData(Object data) { this.data = data; } public static Result success(Object data){ return new Result(1, "success", data); } public static Result success(){ return new Result(1, "success", null); } public static Result error(String msg){ return new Result(0, msg, null); } @Override public String toString() { return "Result{" + "code=" + code + ", msg='" + msg + '\'' + ", data=" + data + '}'; } }
-
改写请求
java@RequestMapping("/simpleParam") public Result simpleParam(String name, int age) { System.out.println(name + ":" + age); return Result.success("Hello World"); }
2.3.综合练习
获取员工数据,返回统一响应结果,在页面中渲染(相关资料可以在黑马官方公众号下载)
-
在pom.xml文件中引入dom4j的依赖,用于解析XML文件
xml<!-- 解析xml --> <dependency> <groupId>org.dom4j</groupId> <artifactId>dom4j</artifactId> <version>2.1.3</version> </dependency>
-
引入资料中提供的解析XML的工具类XMLParserUtils、对应的实体类Emp、XML文件 emp.xml
-
引入资料中提供的静态页面文件,放在resources下的static目录下
-
编写Controller程序,处理请求,响应数据
java@RestController public class EmpController { @RequestMapping("/listEmp") public Result list() { // 1. 加载解析xml String file = "D:\\桌面\\Java\\Java(下)\\spring_demo\\src\\main\\resources\\emp.xml"; List<Emp> empList = XmlParserUtils.parse(file, Emp.class); // 2. 对数据进行转换处理 empList.forEach(emp -> { String gender = emp.getGender(); if("1".equals(gender)) { emp.setGender("男"); }else if("2".equals(gender)) { emp.setGender("女"); } String job = emp.getJob(); if("1".equals(job)) { emp.setJob("教师"); }else if("2".equals(job)) { emp.setGender("学生"); } }); // 3. 响应数据 return Result.success(empList); } }
-
尝试发送请求
-
通过浏览器访问前端页面
3.三层架构
在上一节的综合练习中,代码的不同的业务逻辑写在了一起,导致代码复用性差,难以维护

为此设计了三层架构来优化
功能分类 | 对应层 | 说明 |
---|---|---|
数据访问 | controller(控制层) | 接收前端发送的请求,对请求进行处理,并响应数据 |
逻辑处理 | service(业务逻辑层) | 处理具体的业务逻辑 |
接收请求、响应数据 | dao(数据访问层,Data Access Object) | 数据访问操作(包括增、删、改、查) |
controller => service => dao (=>表示调用关系)
3.1.三层拆分
我们将上面三部分的代码分别写到对应层,每个对应层有一个接口(要做的事情),每个接口可以有若干个实现方案(实现类)

-
数据访问层(dao)
java// 接口 public interface Empdao { // 获取员工列表 public List<Emp> empList(); }
java// 实现类 public class EmpDaoA implements Empdao { @Override public List<Emp> empList() { // 1. 加载解析xml String file = "D:\\桌面\\Java\\Java(下)\\spring_demo\\src\\main\\resources\\emp.xml"; List<Emp> empList = XmlParserUtils.parse(file, Emp.class); return empList; } }
-
业务逻辑层(service)
java// 接口 public interface EmpService { public List<Emp> empList(); }
java// 实现类 public class EmpServiceA implements EmpService { private Empdao empdao = new EmpDaoA(); @Override public List<Emp> empList() { // 调用dao层接口 List<Emp> empList = empdao.empList(); // 2. 对数据进行转换处理 empList.forEach(emp -> { String gender = emp.getGender(); if("1".equals(gender)) { emp.setGender("男"); }else if("2".equals(gender)) { emp.setGender("女"); } String job = emp.getJob(); if("1".equals(job)) { emp.setJob("教师"); }else if("2".equals(job)) { emp.setGender("学生"); } }); return empList; } }
-
控制层(controller)
java@RestController public class EmpController { private EmpService empService = new EmpServiceA(); @RequestMapping("/listEmp") public Result list() { // 3. 响应数据 return Result.success(empService.empList()); } }
3.2.分层解耦
- 内聚:软件中各个功能模块内部的功能联系。
- 耦合:衡量软件中各个层/模块之间的依赖、关联的程度。
- 软件设计原则:高内聚低耦合
在上节的三层拆分中,三个层级耦合性比较高,我们要降低耦合性
控制反转(IOC):对象的创建控制器由程序自身转移到外部(容器),通过
@Component
注解实现
依赖注入(DI):容器为应用程序提供运行时所依赖的资源,通过@Autowired
注解实现
-
Service层、Dao层的实现类,交给IOC容器管理(控制反转)
java// Service层 @Component public class EmpServiceA implements EmpService { private Empdao empdao; // ... }
java// Dao层 @Component public class EmpDaoA implements Empdao { // ... }
-
为Controller层、Service层注入运行时依赖的对象(依赖注入)
java@RestController public class EmpController { @Autowired private EmpService empService; // ... }
java// Service层 @Component public class EmpServiceA implements EmpService { @Autowired // 程序在运行时,IOC容器会提供该类型的bean对象,并赋值给该变量 private Empdao empdao; // ... }
3.3.补充
注解 | 声明 | 位置 |
---|---|---|
@Component | bean的基础注解 | 不属于以下三类时,用此注解(eg:工具类) |
@Controller | @Component的衍生注解 | 标注在控制器类上(@RestController注解已包括,一般不写) |
@Service | @Component的衍生注解 | 标注在业务逻辑类上 |
@Repository | @Component的衍生注解 | 标注在数据访问类上(由于与mybatis整合,用的少) |
了解:
- 声明bean的时候,可以通过value属性指定bean的名字,如果没有指定,默认为类名首字母小写。
- 前面声明bean的四大注解,要想生效,还需要被组件扫描注解@ComponentScan扫描。
- @ComponentScan注解虽然没有显式配置,但是实际上已经包含在了启动类声明注解 @SpringBootApplication 中,默认扫描的范围是++启动类所在包及其子包++。