当前位置: 首页 > article >正文

从Spring请求处理到分层架构与IOC:注解详解与演进实战

引言

        在Spring开发中,请求参数处理、统一响应格式、分层架构设计以及依赖管理是构建可维护应用的核心要素。然而,许多开发者在实践中常面临以下问题:

  • 如何规范接收不同格式的请求参数?

  • 为何要引入分层架构?

  • 什么是控制反转(IoC)和依赖注入(DI)?

  • Spring的注解如@RestController@RequestBody等有何区别?

        本文将通过一个完整的案例演进,从基础请求处理出发,逐步引入分层架构与IoC容器,结合注解的深度解析,最终实现高内聚、低耦合的代码结构。过程中会详细讲解Bean对象管理组件扫描机制,以及常用注解的核心用法。

一、请求参数处理与统一响应

1. 请求参数接收方式

这里用Postman作为测试工具

(1) 简单参数:@RequestParam

简单post请求

 

 //保证参数名和请求参数名一致,或者用@RequestParam注解指定参数名
    @RequestMapping(value = "/simpleParam")
    public String simpleParam(String name, int age) {
        System.out.println(name + ": " + age);
        return "success";
    }
  • @RequestParam:绑定请求参数到方法参数,支持:

    • name:指定参数名(若省略则默认匹配方法参数名)

    • defaultValue:设置默认值

  • 测试URLhttp://localhost:8080/user?name=Tom&age=20

 (2)简单实体参数

        如果传入参数太多,我们可以进行实体化再进行传入,需要注意的是,传递的参数名字和接口方法里的参数名字需要对应,否则就需要用上面提到的@RequestParam进行指定

 User类

package com.ffyc.entity;


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 Address getAddress() {
        return address;
    }

    public void setAddress(Address address) {
        this.address = address;
    }

    public Integer getAge() {
        return age;
    }

    public void setAge(Integer age) {
        this.age = age;
    }

    @Override
    public String toString() {
        return "User{" +
                "name='" + name + '\'' +
                ", age=" + age +
                ", address=" + address +
                '}';
    }



}
 //简单实体参数
    @RequestMapping(value = "/simpleEnt")
    public String simpleEnt(User user) {
        System.out.println(user);
        return  "success";
    }
(3)复杂实体参数 

        假如我们需要传递用户的,姓名,年龄和地址,而地址作为一个新的对象,包含省份,城市,需要传递这些复杂的实体参数

Address类

package com.ffyc.entity;


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 + '\'' +
                '}';
    }
}
    //复杂实体参数
    @RequestMapping(value = "/complexEnt")
    public String complexEnt(User user) {
        System.out.println(user);
        return  "success";
    }
(4)数组参数/集合参数

比如遇到复选框时我们可以选择数组,或者集合(list)进行传递

hobbies对应方法中的hobbies 

    //数组参数
    @RequestMapping(value = "/arrayParam")
    public String arrayParam(String[] hobbies) {
        System.out.println(Arrays.toString(hobbies));
        return "success";
    }

 用list集合进行传递

 hobby需要对应

    //集合参数
    @RequestMapping(value = "/collectionParam")
    public String collectionParam(@RequestParam List<String>hobby) {
        System.out.println(hobby);
        return "success";
    }
 (5)时间日期参数

    //时间日期参数
    @RequestMapping(value = "/dateParam")
    public String dateParam(@DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss") LocalDateTime updateTime ) {
        System.out.println(updateTime);
        return "success";
    }

需要用到@DateTimeFormat注解指定格式再进行传递

(6)JSON参数

    //JSON参数
    @RequestMapping(value = "/jsonParam")
    public String jsonParam(@RequestBody User user) {
        System.out.println(user);
        return "success";
    }

@RequestBody: 将请求体中的JSON反序列化为Java对象

 (7)路径参数

有时候传递的参数再路径中

    //路径参数
    @RequestMapping(value = "/pathParam/{id}")
    public String pathParam(@PathVariable("id") Integer id) {
        System.out.println(id);
        return "success";
    }

@PathVariable:从URL路径中提取参数

 2. 统一响应格式

统一规范,方便前后端数据交互

响应实体类定义

@Data
@AllArgsConstructor
public class Result<T> {
    private int code;
    private String message;
    private T data;

    public static <T> Result<T> success(T data) {
        return new Result<>(200, "success", data);
    }
}

使用@ResponseBody返回JSON

@GetMapping("/user/{id}")
@ResponseBody
public Result<User> getUser(@PathVariable Long id) {
    User user = userService.findById(id);
    return Result.success(user);
}

3. @Controller vs @RestController

 代码对比

// 传统Controller返回视图
@Controller
public class PageController {
    @GetMapping("/home")
    public String home() {
        return "index.html"; // 返回视图名称
    }
}

// RestController返回JSON
@RestController
public class UserController {
    @GetMapping("/api/user")
    public User getUser() {
        return new User("Tom", 20); // 自动转为JSON
    }
}

 

二、Bean管理与组件扫描

1. Bean对象的概念

  • 定义:由Spring容器管理的对象,生命周期由容器控制

  • 创建方式

    • 通过@Component及其派生注解(@Service@Repository@Controller)标记类

    • 通过@Bean方法在配置类中显式定义

2. 组件扫描:@ComponentScan

  • 作用:指定Spring扫描的包路径,自动注册标记了@Component的类为Bean

  • Spring Boot默认行为

    • @SpringBootApplication已包含@ComponentScan

    • 默认扫描主类所在包及其子包

手动配置示例

@Configuration
@ComponentScan(basePackages = "com.example.service")
public class AppConfig { }

三、分层架构演进

1. 原始单层架构的问题

高度耦合的Controller

@RestController
public class UserController {
    // 直接操作数据库(违反分层原则)
    @Autowired
    private JdbcTemplate jdbcTemplate;

    @GetMapping("/user/{id}")
    public User getUser(@PathVariable Long id) {
        String sql = "SELECT * FROM user WHERE id = ?";
        return jdbcTemplate.queryForObject(sql, new UserRowMapper(), id);
    }
}

缺陷

  • 业务逻辑与数据访问混杂

  • 难以复用和维护

2. 三层架构改造

(1) 分层结构

(2) 分层代码实现

DAO层

@Repository
public class UserDaoImpl implements UserDao {
    @Autowired
    private JdbcTemplate jdbcTemplate;

    @Override
    public User findById(Long id) {
        String sql = "SELECT * FROM user WHERE id = ?";
        return jdbcTemplate.queryForObject(sql, new UserRowMapper(), id);
    }
}

Service层

@Service
public class UserServiceImpl implements UserService {
    private final UserDao userDao;

    @Autowired // 构造器注入(推荐)
    public UserServiceImpl(UserDao userDao) {
        this.userDao = userDao;
    }

    @Override
    public User findById(Long id) {
        return userDao.findById(id);
    }
}

Controller层

@RestController
@RequestMapping("/api/users")
public class UserController {
    private final UserService userService;

    @Autowired
    public UserController(UserService userService) {
        this.userService = userService;
    }

    @GetMapping("/{id}")
    public Result<User> getUser(@PathVariable Long id) {
        User user = userService.findById(id);
        return Result.success(user);
    }
}

3. 分层优势

四、IoC与依赖注入优化

1. 紧耦合问题演示

// 直接依赖具体实现类
public class UserServiceImpl implements UserService {
    private UserDao userDao = new UserDaoImpl(); // 紧耦合
}

问题

  • 更换DAO实现需修改代码

  • 难以进行单元测试

 2.控制反转 IOC

没有什么是加一个中间层不能解决的

 

 容器里面的队象成为Bean,默认是该类的名字首字母小写,例如,类的名字叫 EmpService,那么对应的Bean对象的就是 empService ,可以通过 value属性进行指定名字,不过一般用不到

@Service
public class UserServiceImpl implements UserService {
    @Autowired
    private UserDao userDao;
}

 3.依赖注入 DI

用法区别

一个支付系统支持微信支付和支付宝支付

public interface PaymentGateway {
    void pay();
}

@Component("wechatPay") // Bean名称=wechatPay
public class WechatPay implements PaymentGateway {
    @Override
    public void pay() {
        System.out.println("微信支付");
    }
}

@Component("alipay") // Bean名称=alipay
public class Alipay implements PaymentGateway {
    @Override
    public void pay() {
        System.out.println("支付宝支付");
    }
}

使用@Autowired + @Qualifier

@Service
public class PaymentService {
    @Autowired
    @Qualifier("wechatPay")
    private PaymentGateway paymentGateway;
}

使用@Resource

@Service
public class PaymentService {
    @Resource(name = "wechatPay")
    private PaymentGateway paymentGateway;
}

五、总结

        掌握从基础请求处理到分层架构设计的完整路径,理解Spring的IoC容器与依赖注入机制,是构建松耦合、高可维护应用的关键。


http://www.kler.cn/a/519923.html

相关文章:

  • MYSQL数据库 - 启动与连接
  • 入门 Canvas:Web 绘图的强大工具
  • C#,入门教程(05)——Visual Studio 2022源程序(源代码)自动排版的功能动画图示
  • rust学习-rust中的格式化打印
  • 深度解读:近端策略优化算法(PPO)
  • 浅谈在AI时代GIS的发展方向和建议
  • Elasticsearch 性能测试工具 Loadgen 之 004——高级用法示例
  • c语言函数(详解)
  • Vue.js 高级组件开发
  • 任务一:Android逆向
  • 泷羽Sec-Powershell3
  • 设计模式思想的元规则
  • Python从0到100(八十五):神经网络与迁移学习在猫狗分类中的应用
  • 数据结构day02
  • go安全项目汇总表
  • 神经网络|(三)线性回归基础知识
  • Leetcode - 周赛433
  • 【算法学习】分治法应用—归并排序
  • Springboot 的启动流程【超级详细 | 附带思维导图】
  • 左右互博02-unidbg主动调用外层so函数