ARTICLE DETAIL

资讯详情

深耕编程入门与网站建设的一线实战洞察。

SpringBoot Web开发全解:项目创建、HTTP协议、请求响应、DI依赖注入、IOC、DI、三层架构

SpringBoot Web开发全解:项目创建、HTTP协议、请求响应、DI依赖注入、IOC、DI、三层架构 一、Web基础架构 B/S 和 C/SWeb开发分为B/S架构与C/S架构浏览器与服务器之间数据传输基于HTTP协议。B/S架构 Browser/Server浏览器/服务器客户端只需要浏览器程序逻辑、数据全部存放在服务端。✅优点维护方便只需要更新服务端客户端无需安装升级。❌缺点体验一般。B/S架构区分静态资源、动态资源静态资源内容不会随请求发生变化。HTML、CSS、JS、图片、视频负责页面展示。动态资源服务器根据请求动态生成每次请求内容可能变化Spring框架负责业务逻辑处理。C/S架构 Client/Server客户端/服务器需要单独下载、安装客户端软件例如QQ、桌面APP。✅优点用户体验好。❌缺点客户端需要单独开发维护版本升级麻烦。C/S架构交互流程浏览器发送HTTP请求 → Tomcat Web服务器服务器返回静态/动态资源给浏览器。二、SpringBoot项目创建脚手架连接失败解决方案IDEA中使用Spring Initializr创建SpringBoot项目默认地址https://start.spring.io。国内访问经常超时报错Connect timed out。解决方案切换阿里云镜像地址Server URL修改为https://start.aliyun.com切换阿里云脚手架即可正常创建SpringBoot项目。三、SpringBoot入门项目剖析starter起步依赖疑问为什么仅仅一个main方法就可以启动Web应用核心在于starter起步依赖starter把开发需要的一堆依赖全部封装我们只需要引入一个starter自动导入全部相关jar包。常用starterspring‑boot‑starter‑webweb开发起步依赖内部自动包含tomcat、spring‑mvc、json序列化等web开发全套依赖。spring‑boot‑starter‑test单元测试起步依赖提供测试相关依赖包。pom.xml关键依赖示例dependencygroupIdorg.springframework.boot/groupIdartifactIdspring-boot-starter-web/artifactId/dependencydependencygroupIdorg.springframework.boot/groupIdartifactIdspring-boot-starter-test/artifactIdscopetest/scope/dependency项目目录结构SpringbootWebQuickstartApplication项目启动类main方法入口。resources配置文件、静态资源存放目录。pom.xmlmaven依赖配置文件。四、HTTP协议详解HTTPHyper Text Transfer Protocol超文本传输协议规定浏览器和服务器之间数据传输的规则。HTTP三大特点基于TCP协议面向连接传输安全。请求‑响应模型一次请求对应一次响应。浏览器发请求服务器返回响应。无状态协议协议本身没有记忆能力每一次请求响应互相独立。✅优点速度快。❌缺点多次请求之间无法共享数据后续使用Cookie、Session解决。五、HTTP请求数据格式与GET/POST区别HTTP请求数据分为三大部分请求行请求方式 资源路径 HTTP协议版本第一行请求头key:value键值对描述浏览器环境信息多行。请求体POST请求存放请求参数GET没有请求体。常见请求头说明请求头作用Host请求访问的主机名端口User‑Agent浏览器版本信息Accept浏览器可以接收哪些类型响应数据Accept‑Language浏览器偏好语言Accept‑Encoding浏览器支持的压缩格式Content‑Type请求体的数据类型Content‑Length请求体字节大小GET请求示例GET /brand/findAll?nameOPPOstatus1 HTTP/1.1 Accept: text/html,application/xhtmlxml Host: localhost:8080 User‑Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) ChromeGET参数拼接在请求行URL后面没有请求体浏览器对GET请求数据大小有限制。POST请求示例POST /brand HTTP/1.1 Accept: application/json Content‑Type: application/json;charsetUTF‑8 Host: localhost:8080 User‑Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) Chrome {status:1,brandName:黑马,companyName:黑马程序员}POST参数放在请求体数据大小没有限制。六、SpringBoot获取HTTP请求数据Tomcat服务器接收到HTTP请求自动解析原始协议数据封装成HttpServletRequest对象传递给Controller方法。我们不需要手动解析HTTP报文直接使用对象API获取数据。代码示例importjakarta.servlet.http.HttpServletRequest;importorg.springframework.web.bind.annotation.RequestMapping;importorg.springframework.web.bind.annotation.RestController;RestControllerpublicclassHelloController{RequestMapping(/request)publicStringrequest(HttpServletRequestrequest){//1.获取请求参数Stringnamerequest.getParameter(name);//2.获取请求URI、URLStringurirequest.getRequestURI();Stringurlrequest.getRequestURL().toString();//3.获取请求头StringuserAgentrequest.getHeader(User‑Agent);//4.获取请求方式 GET / POSTStringmethodrequest.getMethod();//5.获取查询字符串StringqueryStringrequest.getQueryString();System.out.println(name:name);System.out.println(uri:uri);System.out.println(url:url);System.out.println(浏览器信息:userAgent);System.out.println(请求方式:method);System.out.println(查询参数:queryString);returnrequest success;}}七、HTTP响应数据格式与状态码HTTP响应也分为响应行、响应头、响应体。响应状态码分类状态码分类含义1xx临时状态码请求已接收继续处理2xx成功请求处理完成如2003xx重定向让客户端重新发起请求如3024xx客户端错误责任在浏览器。404资源找不到、401未授权5xx服务端错误服务端代码抛出异常500常用响应头响应头作用Content‑Type响应返回数据类型application/json、text/htmlContent‑Length响应内容字节长度Content‑Encoding数据压缩格式gzipCache‑Control浏览器缓存控制Set‑Cookie给浏览器设置Cookie八、SpringBoot设置响应数据两种方式方式1HttpServletResponseimportjakarta.servlet.http.HttpServletResponse;importorg.springframework.web.bind.annotation.RequestMapping;importorg.springframework.web.bind.annotation.RestController;importjava.io.Exception;RestControllerpublicclassResponseController{RequestMapping(/response)publicvoidresponse(HttpServletResponseresponse)throwsException{//1.设置响应状态码response.setStatus(401);//2.设置响应头response.setHeader(name,bit);//3.设置响应体response.getWriter().write(h1Hello Response/h1);}}方式2ResponseEntitySpring推荐返回ResponseEntity对象可以链式设置状态码、响应头、响应体。importorg.springframework.http.ResponseEntity;importorg.springframework.web.bind.annotation.RequestMapping;importorg.springframework.web.bind.annotation.RestController;RestControllerpublicclassResponseController{RequestMapping(/response2)publicResponseEntityStringresponseEntity(){returnResponseEntity.status(401).header(group,itcast).body(h1Hello Response/h1);}}九、耦合、内聚耦合模块/层之间依赖关联程度耦合越低越好内聚模块内部功能联系内聚越高越好原始代码Controller中new UserServiceImpl()硬编码new对象耦合度高。如果实现类改名字所有new的地方全部要修改。IOC控制反转 Inversion Of Control对象创建的控制权从程序代码交给Spring IOC容器不再自己new。交给容器管理的对象叫Bean。DI依赖注入 Dependency InjectionIOC容器在运行时自动把依赖的Bean注入给需要的类。IOC是思想DI是实现IOC的手段。十、Spring DI依赖注入 Autowired三种注入方式DIDependency Injection依赖注入Spring IOC容器将容器中的Bean自动装配到类中。Autowired默认按类型byType注入。① 属性注入字段注入RestControllerpublicclassUserController{AutowiredprivateUserServiceuserService;}✅优点代码简洁写demo开发快。❌缺点隐藏依赖关系破坏封装不推荐生产环境。② 构造函数注入【Spring官方推荐】RestControllerpublicclassUserController{privatefinalUserServiceuserService;AutowiredpublicUserController(UserServiceuserService){this.userServiceuserService;}}✅优点依赖一目了然可以用final修饰保证不可变线程安全单元测试友好。❌缺点依赖参数过多构造函数臃肿。重点类中只有一个构造函数Autowired注解可以省略Spring自动调用构造器注入。③ Setter注入RestControllerpublicclassUserController{privateUserServiceuserService;AutowiredpublicvoidsetUserService(UserServiceuserService){this.userServiceuserService;}}✅优点封装良好适合可选依赖。❌缺点需要手写setter增加代码量。最佳实践业务代码优先构造函数注入项目中可以搭配LombokRequiredArgsConstructor简化final字段构造函数。三种注入对比注入方式优点缺点适用场景属性注入代码简洁快速开发隐藏依赖破坏封装测试Demo禁止线上业务构造函数注入依赖显性可见、final不可变参数多时代码臃肿生产环境首选必填依赖Setter注入封装好支持动态替换依赖手写setter代码量大可选依赖场景十一、多Bean冲突问题以及三种解决方案Autowired默认按照类型注入。当一个接口存在多个实现类Spring容器中存在多个同类型Bean直接Autowired会抛出异常。报错信息Field userService in com.itheima.controller.UserController required a single bean, but 2 were found: - userServiceImpl - userServiceImpl2含义期望1个Bean但是容器找到2个Spring不知道选择哪一个。方案1Primary写在实现类标记优先Bean多个同类型Bean优先选择被Primary修饰的实现Controller无需修改。PrimaryServicepublicclassUserServiceImplimplementsUserService{//业务逻辑}方案2Autowired Qualifier(bean名称)在注入点指定Bean名字精准匹配。RestControllerpublicclassUserController{AutowiredQualifier(userServiceImpl)privateUserServiceuserService;}方案3Resource(namebean名称)Resource是Java JSR‑250规范注解不属于Spring优先按名称byName注入。RestControllerpublicclassUserController{Resource(nameuserServiceImpl)privateUserServiceuserService;}Autowired 和 Resource区别AutowiredSpring提供默认byType按类型注入搭配Qualifier指定bean名称。ResourceJava官方规范优先byName按名称注入名称找不到才降级按类型。十二、三层架构Controller控制层接收前端请求响应返回数据Service业务逻辑层处理业务逻辑Dao数据访问层负责数据读写文件/数据库增删改查原始写法问题把读取文件、解析数据全部写在Controller里面缺点复用性差、耦合高、难以维护优化拆分三层Controller调用ServiceService调用Dao各司其职十三、完整分层代码示例1. Dao接口 Dao实现类// UserDao接口publicinterfaceUserDao{ListStringlist();}Repository//交给IOC管理publicclassUserDaoImplimplementsUserDao{OverridepublicListStringlist()throwsIOException{InputStreaminthis.getClass().getClassLoader().getResourceAsStream(user.txt);returnIoUtil.readLines(in,StandardCharsets.UTF_8,newArrayList());}}2. Service接口 Service实现类publicinterfaceUserService{ListUserlist();}ServicepublicclassUserServiceImplimplementsUserService{AutowiredprivateUserDaouserDao;OverridepublicListUserlist(){ListStringlinesuserDao.list();//解析每行字符串封装User对象returnlines.stream().map(line-{String[]splitline.split(,);IntegeridInteger.parseInt(split[0]);Stringusernamesplit[1];Stringpasswordsplit[2];Stringnamesplit[3];IntegerageInteger.parseInt(split[4]);LocalDateTimetimeLocalDateTime.parse(split[5],DateTimeFormatter.ofPattern(yyyy‑MM‑dd HH:mm:ss));returnnewUser(id,username,password,name,age,time);}).toList();}}3. ControllerRestControllerpublicclassUserController{AutowiredprivateUserServiceuserService;RequestMapping(/list)publicListUserlist(){returnuserService.list();}}
返回列表