Web请求响应
简单参数:在向服务器发起请求时,向服务器传递的是一些普通的请求数据。
那么在后端程序中,如何接收传递过来的普通参数数据呢?
简单参数
@RestController
public class RequestController {
// http://localhost:8080/simpleParam?name=Tom&age=10
// 第1个请求参数: name=Tom 参数名:name,参数值:Tom
// 第2个请求参数: age=10 参数名:age , 参数值:10
//springboot方式
@RequestMapping("/simpleParam")
public String simpleParam(String name , Integer age ){//形参名和请求参数名保持一致
System.out.println(name+" : "+age);
return "OK";
}
}
postman测试( GET 请求):
postman测试( POST请求 ):
实体参数
定义实体参数User
public class User {
private String name;
private Integer age;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Integer getAge() {
return age;
}
public void setAge(Integer age) {
this.age = age;
}
@Override
public String toString() {
return "User{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
}
Controller方法:
@RestController
public class RequestController {
//实体参数:简单实体对象
@RequestMapping("/simplePojo")
public String simplePojo(User user){
System.out.println(user);
return "OK";
}
}
Postman测试:
-
参数名和实体类属性名一致时
-
参数名和实体类属性名不一致时
复杂实体对象
定义POJO实体类:
-
Address实体类
public class Address {
private String province;
private String city;
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 + '\'' +
'}';
}
}
-
User实体类
public class User {
private String name;
private Integer age;
private Address address; //地址对象
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Integer getAge() {
return age;
}
public void setAge(Integer age) {
this.age = age;
}
public Address getAddress() {
return address;
}
public void setAddress(Address address) {
this.address = address;
}
@Override
public String toString() {
return "User{" +
"name='" + name + '\'' +
", age=" + age +
", address=" + address +
'}';
}
}
Controller方法:
@RestController
public class RequestController {
//实体参数:复杂实体对象
@RequestMapping("/complexPojo")
public String complexPojo(User user){
System.out.println(user);
return "OK";
}
}
Postman测试:
数组参数
@RestController
public class RequestController {
//数组集合参数
@RequestMapping("/arrayParam")
public String arrayParam(String[] hobby){
System.out.println(Arrays.toString(hobby));
return "OK";
}
}
Postman测试:
在前端请求时,有两种传递形式:
方式一: xxxxxxxxxx?hobby=game&hobby=java
方式二:xxxxxxxxxxxxx?hobby=game,java
集合参数
Controller方法:
@RestController
public class RequestController {
//数组集合参数
@RequestMapping("/listParam")
public String listParam(@RequestParam List<String> hobby){
System.out.println(hobby);
return "OK";
}
}
Postman测试:
方式一: xxxxxxxxxx?hobby=game&hobby=java
方式二:xxxxxxxxxxxxx?hobby=game,java
日期参数
Controller方法:
@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";
}
}
Postman测试:
JSON参数
实体类:Address
public class Address {
private String province;
private String city;
//省略GET , SET 方法
}
实体类:User
public class User {
private String name;
private Integer age;
private Address address;
//省略GET , SET 方法
}
Controller方法:
@RestController
public class RequestController {
//JSON参数
@RequestMapping("/jsonParam")
public String jsonParam(@RequestBody User user){
System.out.println(user);
return "OK";
}
}
Postman测试:
分层解耦
三层架构
SpringBoot框架支持三层架构模式,这有助于提高代码的可维护性和可扩展性。以下是SpringBoot中三层架构的详细说明:
- 表示层(Presentation Layer):也被称为Web层或控制层。这一层主要负责接收客户端的请求并向客户端发送响应。在Spring Boot应用中,这一层通常由Controller组件构成,它们处理HTTP请求,调用业务逻辑层的服务,并返回响应数据。
- 业务逻辑层(Business Logic Layer):也称为Service层。它处理应用程序的核心业务逻辑,比如数据的处理和计算。这一层为表示层提供必要的业务方法,并调用数据访问层来持久化数据。
- 数据访问层(Data Access Layer):也称为DAO层或持久层。负责与数据库交互,执行数据的增删改查操作。这一层为业务逻辑层提供数据支持,并将业务对象映射到数据库表中。
此外,每一层都有明确的职责,彼此之间通过接口进行通信,确保了系统的高内聚和低耦合。这种分层方式有利于后期的维护和项目的扩展。
耦合问题
在SpringBoot的三层架构中,耦合问题通常指的是不同层之间的依赖关系过于紧密,导致一个层的变动可能会影响到其他层。为了解决这一问题,可以采取以下措施:
- 遵循单一职责原则:确保每个类或方法只负责一项任务,这样可以减少不同组件之间的依赖,提高代码的可读性和可维护性。
- 使用接口或抽象类:通过定义清晰的接口或抽象类来隔离各层之间的直接依赖,使得上层不需要知道下层的具体实现细节。
- 依赖注入:利用Spring框架的依赖注入特性,可以实现层与层之间的松耦合。这样可以在不修改上层代码的情况下,替换或修改下层的实现。
- 避免循环依赖:确保不存在从一个层到另一个层的直接或间接的循环依赖关系,这样可以避免复杂的依赖结构。
- 分层解耦:保持每一层的职责清晰分离,比如表现层只处理用户交互,业务逻辑层处理业务规则,数据访问层处理数据持久化等。
- 编码规范:制定和遵循一套编码规范,确保团队成员在开发时能够一致地应用解耦的最佳实践。
- 持续重构:随着项目的进展,不断地对代码进行重构,以提高代码质量,降低耦合度。
- 单元测试:编写单元测试可以帮助识别和隔离耦合问题,因为紧密耦合的代码通常难以进行单元测试。
- 文档和培训:通过编写文档和进行培训,帮助团队成员理解耦合问题以及如何避免它们,从而提高整个团队的软件开发能力。
IOC&DI
-
Controller层:
@RestController
public class EmpController {
@Autowired //运行时,从IOC容器中获取该类型对象,赋值给该变量
private EmpService empService ;
@RequestMapping("/listEmp")
public Result list(){
//1. 调用service, 获取数据
List<Emp> empList = empService.listEmp();
//3. 响应数据
return Result.success(empList);
}
}
-
Service层:
@Component //将当前对象交给IOC容器管理,成为IOC容器的bean
public class EmpServiceA implements EmpService {
@Autowired //运行时,从IOC容器中获取该类型对象,赋值给该变量
private EmpDao empDao ;
@Override
public List<Emp> listEmp() {
//1. 调用dao, 获取数据
List<Emp> empList = empDao.listEmp();
//2. 对数据进行转换处理 - gender, job
empList.stream().forEach(emp -> {
//处理 gender 1: 男, 2: 女
String gender = emp.getGender();
if("1".equals(gender)){
emp.setGender("男");
}else if("2".equals(gender)){
emp.setGender("女");
}
//处理job - 1: 讲师, 2: 班主任 , 3: 就业指导
String job = emp.getJob();
if("1".equals(job)){
emp.setJob("讲师");
}else if("2".equals(job)){
emp.setJob("班主任");
}else if("3".equals(job)){
emp.setJob("就业指导");
}
});
return empList;
}
}
- Dao层:
@Component //将当前对象交给IOC容器管理,成为IOC容器的bean
public class EmpDaoA implements EmpDao {
@Override
public List<Emp> listEmp() {
//1. 加载并解析emp.xml
String file = this.getClass().getClassLoader().getResource("emp.xml").getFile();
System.out.println(file);
List<Emp> empList = XmlParserUtils.parse(file, Emp.class);
return empList;
}
}
IOC详解
SpringBoot中的IoC(Inversion of Control,控制反转)是一种设计原则和编程思想,它的核心思想是将对象的创建、配置和管理交给一个外部的容器来完成,而不是由对象自己或者其使用者来控制。
具体来说,IoC在Spring框架中是通过IoC容器来实现的,这个容器负责:
- 创建对象:容器负责创建应用程序中所需的各种对象,这些对象通常被称为beans。
- 配置管理:容器负责管理这些对象的生命周期,包括它们的初始化、依赖注入以及销毁等。
- 依赖注入:容器通过依赖注入的方式将对象之间的依赖关系解耦,使得对象之间不直接相互依赖,而是依赖于抽象接口或配置文件。
- AOP支持:除了IoC,Spring还提供了AOP(面向切面编程)的支持,允许开发者在不修改源代码的情况下为程序添加额外的功能。
- 整合其他框架:Spring的设计使得它能够方便地与其他框架进行整合,如Hibernate、MyBatis等。
- 事务操作:Spring简化了事务操作的处理,提供了声明式事务管理。
- API开发:Spring降低了API开发的复杂性,使得开发者可以更加专注于业务逻辑的开发。
总的来说,在SpringBoot应用中,通常会使用@SpringBootApplication
注解来标记主类,并通过调用SpringApplication.run()
方法来启动IoC容器。通过这种方式,SpringBoot会自动扫描指定包下的组件,并将它们装配到IoC容器中。
DI详解
依赖注入(Dependency Injection, DI)是Spring框架中的一个核心概念,它也是实现控制反转(Inversion of Control, IoC)的一种手段。以下是对依赖注入的详细解释:
基本概念:
- DI是一种设计模式,用于降低代码之间的耦合度,使得一个对象不需要自己创建或查找它所依赖的其他对象,而是通过外部的方式(如一个配置文件或框架)来提供所需的依赖项。
工作原理:
- 在Spring中,对象的依赖关系是由Spring容器负责管理的。当一个对象需要另一个对象时,它不是自己创建那个对象,而是从容器中获取一个已经配置好的实例。这样做的好处是,如果依赖的对象需要变更,只需要在容器中修改配置,而不用改动依赖它的代码。
实现方式:
- Spring提供了多种方式来实现DI,包括通过XML配置文件、注解(如@Autowired、@Resource等)以及Java配置类。这些方式都可以让开发者指定对象之间的依赖关系。
优点:
- DI提高了代码的可测试性,因为可以很容易地替换或模拟依赖的对象。
- 它也增加了代码的灵活性和可维护性,因为依赖关系的改变只需要在一个地方(即配置文件或注解)进行调整。
与IoC的关系:
- DI是实现IoC的一种方式。IoC是一种更广泛的概念,它描述了控制流的反转,即对象的创建和生命周期管理由程序员转移到了框架。DI则是这种控制反转的具体实现,确保了对象之间的依赖关系由外部管理。
常见问题:
- 在使用DI时,可能会遇到多个候选bean的情况,这时可以使用@Qualifier注解来指定具体使用哪一个bean,或者使用@Primary注解来标记首选的bean。
与其他注解的区别:
- @Autowired和@Resource都可以用于字段注入,但@Autowired是Spring的注解,而@Resource是J2EE的注解。在没有明确指定注入方式时,@Autowired默认通过byType注入,而@Resource默认通过byName注入。