一、SpringBoot Web入门
静态资源:服务器上存储的不会改变的数据,通常不会根据用户的请求而变化。比如:HTML、CSS、JS、图片、视频等(负责页面展示)
动态资源:服务器端根据用户请求和其他数据动态生成的,内容可能会在每次请求时都发生变化。比如:Spring框架、已过时(ServIet、JSP)等(负责逻辑处理)
B/S架构:Browser/Server,浏览器/服务器架构模式。客户端只需浏览器,应用程序的逻辑和数据都存在服务器端。(维护方便 体验一般)
c/S架构:Client/Server,客户端/服务器架构模式。需要单独开发维护客户端。(体验不错 开发维护麻烦)
1、概述
官网:spring.io
Spring发展到今天已经形成了一种开发生态圈,Spring提供了若干个子项目,每个项目用于完成特定的功能。
以Spring Framework为中心
将Spring Framework简化为Spring Boot
SpringBoot可以帮助我们非常快速的构建应用程序、简化开发、提高效率。
官方推荐 企业主流
2、入门程序
(1)创建项目
(2)pom.xml文件内容
目前了解即可
<!--父工程--> <parent></parent> <!--项目的坐标和描述信息--> <!--Java的版本--> <properties></properties> <!--引入依赖,版本已在父工程中管理过--> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-webmvc</artifactId> </dependency> <!--单元测试依赖--> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-webmvc-test</artifactId> <scope>test</scope> </dependency> <!-- SpringBoot的打包插件--> <build> <plugins> <plugin> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-maven-plugin</artifactId> </plugin> </plugins> </build>(3)创建请求处理类
package com.itheima; @RestController //标识当前是一个请求处理类 public class HelloController { @RequestMapping("/hello")//请求路径 public String hello(String name){ System.out.println("Hello Controller ... hello : " + name); return "Hello " + name + "~"; } }浏览器访问结果
(4)启动类
package com.itheima; @SpringBootApplication public class SpringbootWebQuickstartApplication { public static void main(String[] args) { SpringApplication.run(SpringbootWebQuickstartApplication.class, args); } }(5)整个项目的管理配置文件
resources目录下的application.properties文件
3、官方骨架连不了解决方案
将国外的地址
改为国内的阿里云的地址
使用魔法也可以
4、入门解析
起步依赖:
有starter标识
spring-boot-starter-web:包含了web应用开发所需要的常见依赖。
spring-boot-starter-test:包含了单元测试所需要的常见依赖。
官方提供的starter:Spring Boot Reference Documentation
引入web就会引入关于web开发的所有依赖。得益于Maven的参数传递
Maven引入的这两个依赖
二、HTTP协议
1、概述
概念:Hyper Text Transfer Protocol,超文本传输协议,规定了浏览器和服务器之间数据传输的规则。
特点:
1.基于TCP协议:面向连接,安全
2.基于请求-响应模型的:一次请求对应一次响应
3.HTTP协议是无状态的协议:对于事务处理没有记忆能力。
每次请求-响应都是独立的。
缺点:多次请求间不能共享数据。
优点:速度快
2、请求协议-数据格式
(1)请求数据格式
请求头和请求体中间隔了一个空行
(2)GET和POST的区别
请求方式-GET:
请求参数在请求行中,没有请求体,如:/brand/findAll?name=OPPO&status=1。GET请求大小在浏览器中是有限制的。
请求方式-POST:
请求参数在请求体中,POST请求大小是没有限制的。
(3)请求头中的key介绍
Host:请求的主机名
User-Agent:浏览器版本,例如Chrome浏览器的标识类似Mozilla/5.0...Chrome/79,IE浏览器的标识类似Mozila/5.0 (Windows NT... like Gecko
Accept:表示浏览器能接收的资源类型,如text/*,image/*或者*/*表示所有;
Accept-Language:表示浏览器偏好的语言,服务器可以据此返回不同语言的网页;
Accept-Encoding:表示浏览器可以支持的压缩类型,例如gzip,deflate等。
Content-Type:请求主体的数据类型。 Content-Length:请求主体的大小(单位:字节)。
3、请求协议-请求数据获取
Web服务器(Tomcat)对HTTP协议的请求数据进行解析,并进行了封装(HttpServletRequest),在调用Controller方法的时候传递给了该方法。
这样,就使得程序员不必直接对协议进行操作,让Web开发更加便捷。
@RestController public class RequestTestController { @RequestMapping("/request") public String request(HttpServletRequest request){ // 1.获取请求参数name, age String name = request.getParameter("name"); // Tom // 2.获取请求路径uri 和 url String uri = request.getRequestURI(); // /request String url = request.getRequestURL().toString(); // http://localhost:8080/request // 3.获取请求头 User-Agent String userAgent = request.getHeader("User-Agent"); // Mozilla/5.0 (Windows NT 10.0; Win64; x64) // 4.获取请求方式 String method = request.getMethod(); // GET // 5.获取请求的查询字符串 String queryString = request.getQueryString(); // name=Tomcat&age=10 return "request success"; } }小结:
1.HTTP请求数据需要程序员自己解析吗?
不需要,Web服务器负责对HTTP请求数据进行解析,并封装为了请求对象
2.如何获取请求数据?
HttpServletRequest对象里面封装了所有的请求信息
4、响应协议-数据格式
(1)响应数据格式
(2)五类状态码
状态码大全:状态 | Status - HTTP 中文开发手册 - 开发者手册 - 腾讯云开发者社区-腾讯云
(3)响应体的key介绍
5、响应协议-响应数据设置
Web服务器对HTTP协议的响应数据进行了封装(HttpServletResponse),并在调用Controller方法的时候传递给了该方法。
这样,就使得程序员不必直接对协议进行操作,让Web开发更加便捷。
方式一、HttpServletResponse原生写法
@RestController public class ResponseController { @RequestMapping("/response") public void response(HttpServletResponse response) throws IOException { // 1.设置响应状态码 response.setStatus(401); // 2.设置响应头 response.setHeader("itheima", "itheima"); // 3.设置响应体 response.getWriter().write("<h1>Hello Response</h1>"); } }方式二:ResponseEntity封装写法(Spring推荐)
@RestController public class ResponseController { @RequestMapping("/response") public ResponseEntity<String> response() { return ResponseEntity.status(401) // 1.设置响应状态码 .header("group", "itcast") // 2.设置响应头 .body("<h1>Hello Response</h1>");// 3.设置响应体 } }注意: 响应状态码和响应头如果没有特殊要求的话,通常不手动设定。服务器会根据请求处理的逻辑,自动设置响应状态码和响应头。
三、SpringBoot Web案例
1、准备工作
创建一个SpringBoot工程,并勾选web依赖、lombok。
引入资料中准备好的用户数据文件(user.txt),及前端静态页面。
定义一个实体类,用来封装用户信息
2、开发服务端程序
接收请求,读取文本数据并响应。
3、具体操作流程
(1)创建项目
勾选两项,并Create创建,没用的文件删掉
(2)引入数据和静态文件
(3)定义实体类
数据类型用包装类,不要用基本数据类型,因为基本数据类型要赋初始值
在资源文件夹下创建pojo文件夹,创建User实体类
@Data//代替set、get方法 @NoArgsConstructor//代替无参构造 @AllArgsConstructor//代替有参构造 public class User { private Integer id; private String username; private String password; private String name; private Integer age; private LocalDateTime updateTime; }(4)整体项目
加载hutool依赖,用于加载并读取txt文件
<dependency> <groupId>cn.hutool</groupId> <artifactId>hutool-all</artifactId> <version>5.8.27</version> </dependency>创建控制层文件
在UserController文件中,操作文件,将文件内容拆分
@ResponseBody注解的作用
- 将controller方法的返回值直接写入HTTP响应体
- 如果是对象或集合,会先转为json,再响应
- @RestController = @Controller +@ResponseBody
@RestController public class UserController { @RequestMapping("/list") public List<User> list(){ //1.加载并读取文件 InputStream in = this.getClass().getClassLoader().getResourceAsStream("user.txt");//获取文件 ArrayList<String> lines = IoUtil.readLines(in, StandardCharsets.UTF_8, new ArrayList<>());//将文件装入集合,并接收返回值。参数为输入、字符类型、装入集合 //2.解析数据,封装成对象 --> 集合 List<User> userList = lines.stream().map(line -> { String[] parts = line.split(",");//以逗号分隔文件 Integer id = Integer.parseInt(parts[0]);//收集分隔结果 String username = parts[1]; String password = parts[2]; String name = parts[3]; Integer age = Integer.parseInt(parts[4]); LocalDateTime updateTime = LocalDateTime.parse(parts[5], DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")); return new User(id, username, password, name, age, updateTime); }).collect(Collectors.toList()); //3.响应数据 //得益于@RestController注解 return userList; } }以上代码复用性差、难以维护
四、分层解耦
用于解决以上代码复用性差、难以维护的问题
1、三层架构
将以上代码拆解成这三层
(1)每一层的职责
controller:控制层,接收前端发送的请求,对请求进行处理,并响应数据。
service:业务逻辑层,处理具体的业务逻辑。
dao:数据访问层(Data AccessObject)(持久层),负责数据访问操作,包括数据的增、删、改、查。
(2)创建三层架构
创建controller文件夹、创建service文件夹、创建dao文件夹
在dao数据访问层创建接口和实现类
在service业务层创建接口和实现类
将以上单文件中的代码分解到这些分层的文件中
2、解耦思路(IOC与DI介绍)
(1)内聚与耦合
耦合:衡量软件中各个层/各个模块的依赖关联程度。
内聚:软件中各个功能模块内部的功能联系。
软件设计原则:高内聚低耦合。
高耦合的原因:每一层都new其它层的对象
降低高耦合:创建一个容器,用于装每一层产生的对象,其他层在容器中调用该对象。
用到的技术包括控制反转和依赖注入
(2)分层解耦的思路
控制反转:Inversion Of Control,简称IOC。对象的创建控制权由程序自身转移到外部(容器),这种思想称为控制反转。
依赖注入:Dependency Injection,简称DI。容器为应用程序提供运行时,所依赖的资源,称之为依赖注入。
Bean对象:lOC容器中创建、管理的对象,称之为Bean。
3、IOC与DI入门
将Dao及Service层的实现类,交给IOC容器管理。
为Controller及Service注入运行时所依赖的对象。
在Dao及Service层实现类上面加@Component注解,表示交给了IOC容器管理(注意是加在实现类上,而不是接口上)
在Controller及Service层实现类下面加@Autowired注解,表示从DI容器中获取了对象
4、IOC详解
(1)其他控制反转的注解
除了使用@Component注解,交给IOC容器还提供了其他三个注解
注意: 声明bean的时候,可以通过注解的value属性指定bean的名字,如果没有指定,默认为类名首字母小写。
@RestController已经包含了@Controller
(2)组件扫描注解
前面声明bean的四大注解,要想生效,还需要被组件扫描注解@ComponentScan扫描。
该注解虽然没有显式配置,但是实际上已经包含在了启动类声明注解@SpringBootApplication中,默认扫描的范围是启动类所在包及其子包。
规范:启动类裸露在外面
5、DI详解一
常见的依赖注入方式
(1).属性注入
企业常用
(2).构造函数注入
(3).setter注入
6、DI详解二
@Autowired注解,默认是按照类型进行注入的。
如果存在多个相同类型的bean,将会报出如下错误:
(1)方案一:@Primary
加在被注入的类上。用于提高优先级
(2)方案二:@Qualifier
加载注入的类上,表示选择哪个类注入
(3)方案三:@Resource
将方案二的两个注解合并为一个注解
@Resource与@Autowired区别?
@Autowired是Spring框架提供的注解,而@Resource是JavaEE规范提供的
@Autowired默认是按照类型注入,而@Resource默认是按照名称注入