Web后端基础篇-第一天

79 阅读13分钟

Web基础知识

静态资源:像HTML、CSS、JS 以及图片、音频、视频等这些资源

动态资源:在服务器端上存储的,会根据用户请求和其他数据动态生成的,内容可能会在每次请求时都发生变化。比如:ServletJSP等(负责逻辑处理)。java程序开发的动态资源来说,我们通常会将这些动态资源部署在Tomcat,这样的Web服务器中运行。 而浏览器与服务器在通信的时候,基本都是基于HTTP协议的。

BS架构:Browser/Server,浏览器/服务器架构模式。客户端只需要浏览器,应用程序的逻辑和数据都存储在服务端。

  • 优点:维护方便
  • 缺点:体验一般

CS架构:Client/Server,客户端/服务器架构模式。需要单独开发维护客户端。

  • 优点:体验不错
  • 缺点:开发维护麻烦

Tomcat/Servlet

SpringBootWeb入门

Spring家族旗下这么多的技术,最基础、最核心的是 SpringFramework。其他的spring家族的技术,都是基于SpringFramework的,SpringFramework中提供很多实用功能

spring全家桶.png

SpringFramework:配置繁琐、入门难度大

SpringBoot:简化配置、快速开发(官方推荐)

SpringBoot创建脚手架

Http协议

HTTP:Hyper Text Transfer Protocol(超文本传输协议),规定了浏览器与服务器之间数据传输的规则。

HTML:超文本标记语言

Http协议特点

  • 基于TCP协议:面向连接/安全
    • TCP是一种面向连接的(建立连接之前是需要经过三次握手)、可靠的、基于字节流的传输层通信协议,在数据传输方面更安全
  • 基于请求-响应模型: 一次请求对应一次响应(先请求后响应)
    • 请求和响应是一一对应关系,没有请求,就没有响应
  • HTTP协议是无状态协议: 对于数据没有记忆能力。每次请求-响应都是独立的
    • 无状态指的是客户端发送HTTP请求给服务端之后,服务端根据请求响应数据,响应完后,不会记录任何信息
      • 缺点: 多次请求间不能共享数据
      • 优点: 速度快
长连接/短连接

HTTP/1.1 是一种网络协议,用于客户端(如浏览器)和服务器之间的通信。它是超文本传输协议(HTTP)的一个版本,广泛用于互联网上的数据传输

请求头:Connection: keep-alive/close

HTTP/1.1 (默认) 支持两种连接方式:持久连接(长连接) 和 非持久连接(短连接)

长连接:减少开销(减少了频繁建立和关闭连接的开销);适合高频率交互

短连接:连接短暂;适合低频率交互;资源占用少

Http请求协议

Get方式请求协议

httpGet请求协议.png

请求行(以上图中红色部分) :HTTP请求中的第一行数据。由:请求方式资源路径协议/版本组成(之间使用空格分隔)

请求头(以上图中黄色部分) :第二行开始,上图黄色部分内容就是请求头。格式为 key: value 形式

请求头含义
Host表示请求的主机名
User-Agent浏览器版本。 例如:Chrome浏览器的标识类似Mozilla/5.0 ...Chrome/79 ,IE浏览器的标识类似Mozilla/5.0 (Windows NT ...)like Gecko
Accept表示浏览器能接收的资源类型,如text/*,image/或者/*表示所有;
Accept-Language表示浏览器偏好的语言,服务器可以据此返回不同语言的网页;
Accept-Encoding表示浏览器可以支持的压缩类型,例如gzip, deflate等。
Content-Type请求主体的数据类型
Content-Length数据主体的大小(单位:字节)

请求体 :存储请求参数,GET请求的请求参数在请求行中,故不需要设置请求体

Post方式请求协议

PostHttp请求协议.png

请求行(以上图中红色部分):包含请求方式资源路径协议/版本

请求头(以上图中黄色部分)

请求体(以上图中绿色部分) :存储请求参数

  • 请求体和请求头之间是有一个空行隔开(作用:用于标记请求头结束)

Get与Post区别

  • get方式的参数在请求行中的资源路径;
  • 请求参数长度有限制;
  • 安全性低,参数与值直接暴露在浏览器的地址栏中

获取请求数据

<dependency>
    <groupId>commons-io</groupId>
    <artifactId>commons-io</artifactId>
    <version>2.11.0</version>
</dependency>
public String requestTest(HttpServletRequest request) throws IOException {
        // 获取 Get 请求中的请求体数据
        // get请求要想获取请求体必须通过读取流,这个流相当于是存储了请求体的数据,
        // 而且要在方法的第一行就读取流才可以,
    	// 因为一旦执行了类似request.getParameter的操作相当于底层会执行读取流的操作,
        // 因为同一个流是不允许多次写或多次读的,所以要想再读取流就不可以了
        String string = IOUtils.toString(request.getInputStream(), "UTF-8");
        System.out.println(string);

        // 请求方式 GET
        System.out.println(request.getMethod());
        // 请求url地址 http://localhost:8080/request
        System.out.println(request.getRequestURL());
        // 请求uri地址 /request
        System.out.println(request.getRequestURI());
        // 请求参数
        System.out.println(request.getParameter("name"));
        // 请求头
        System.out.println(request.getHeader("accept"));
        // 请求协议 http
        System.out.println(request.getProtocol());
        return "Hello " + request.getParameter("name");
    }
Http响应协议

Http响应协议.png Http响应协议.png

响应行(以上图中红色部分):响应数据的第一行。响应行由协议及版本响应状态码状态码描述组成

响应头(以上图中黄色部分):响应数据的第二行开始。格式为key:value形式

Content-Type:表示该响应内容的类型,例如text/html,image/jpeg ;

Content-Length:表示该响应内容的长度(字节数);

Content-Encoding:表示该响应压缩算法,例如gzip ;

Cache-Control:指示客户端应如何缓存,例如max-age=300表示可以最多缓存300秒 ;

Set-Cookie:告诉浏览器为当前页面所在的域设置cookie ;

响应体(以上图中绿色部分): 响应数据的最后一部分。存储响应的数据,响应体和响应头之间有空行隔开

设置响应数据

@RequestMapping("/response")
public void responseTest(HttpServletResponse response) throws IOException {
    // 设置响应码
    response.setStatus(401);
    // 设置响应头
    response.setHeader("age", "25");
    // 设置响应体
    response.setContentType("text/html");
    response.setCharacterEncoding("UTF-8");
    response.getWriter().write("<h1>Hello</h1>");
}

@RequestMapping("/response2")
public ResponseEntity<?> responseTest(){
    return ResponseEntity.status(401)
        .header("age", "25")
        .body("<h1>Hello</h1>");
}

HTTP状态码

状态码分类说明
1xx响应中 --- 临时状态码。表示请求已经接受,告诉客户端应该继续请求或者如果已经完成则忽略
2xx成功 --- 表示请求已经被成功接收,处理已完成
3xx重定向 --- 重定向到其它地方,让客户端再发起一个请求以完成整个处理
4xx客户端错误 --- 处理发生错误,责任在客户端,如:客户端的请求一个不存在的资源,客户端未被授权,禁止访问等
5xx服务器端错误 --- 处理发生错误,责任在服务端,如:服务端抛出异常,路由出错,HTTP版本不支持等

HTTP 状态码分类

1xx-信息性状态码:这些状态码表示临时的响应,通常用于表示服务器已经接收到了请求的一部分,但还需要进一步的信息才能完成请求

  • 100 Continue:服务器已接收到请求头,客户端应继续发送请求体
  • 101 Switching Protocols:服务器根据客户端的请求切换协议。通常用于升级到 WebSocket 协议

2xx-成功状态码:这些状态码表示请求已成功处理

  • 200 OK:请求成功,响应体包含请求的资源
  • 201 Created:请求成功,并且服务器创建了新的资源
  • 202 Accepted:请求已接受,但处理尚未完成
  • 204 No Content:请求成功,但响应体为空
  • 206 Partial Content:请求成功,但只返回了部分资源(通常用于范围请求)

3xx-重定向状态码:这些状态码表示客户端需要采取进一步的行动来完成请求,通常涉及跳转到另一个 URI

  • 301 Moved Permanently:请求的资源已永久移动到新的 URI(永久重定向)
  • 302 Found:请求的资源临时移动到新的 URI(临时重定向)
  • 304 Not Modified:请求的资源未修改,客户端可以使用缓存的版本
  • 307 Temporary Redirect:请求的资源临时移动到新的 URI,但方法和请求体不变
  • 308 Permanent Redirect:请求的资源已永久移动到新的 URI,但方法和请求体不变

4xx-客户端错误状态码:这些状态码表示客户端请求有误,导致服务器无法处理

  • 400 Bad Request:请求语法错误或请求参数无效(缺少参数;参数格式不合法)
  • 401 Unauthorized:请求未授权,需要身份验证(未登录)
  • 403 Forbidden:服务器理解请求,但拒绝执行(登录,但没有权限)
  • 404 Not Found:请求的资源未找到(请求路径有误)
  • 405 Method Not Allowed:请求方法不被允许(请求方法不匹配)
  • 406 Not Acceptable:请求的内容无法满足客户端(返回内容客户端不可接受)
  • 408 Request Timeout:服务器等待请求超时
  • 412 :请求类型 content-type 有误
  • 429 Too Many Requests:客户端发送的请求过多,触发了限流机制
  • 431 Request Header Fields Too Large:请求头太大

5xx-服务器错误状态码:这些状态码表示服务器在处理请求时发生了错误

  • 500 Internal Server Error:服务器内部错误,无法完成请求(服务端有bug)
  • 501 Not Implemented:服务器不支持请求的方法
  • 502 Bad Gateway:服务器作为网关或代理时,从上游服务器接收到无效响应(代理服务器正常,网络也正常,但是后端服务器没有启动)
  • 503 Service Unavailable:服务器暂时无法处理请求(通常由于过载或维护)(代理服务器负载高或者资源紧张)
  • 504 Gateway Timeout:服务器作为网关或代理时,上游服务器响应超时(代理服务器一定时间内没有接收到返回报文)
  • 505 HTTP Version Not Supported:服务器不支持请求的 HTTP 版本

HTTP方法

八种方法:GET、POST、PUT、DELETE、PATCH、HEAD、OPTIONS、TRACE(后面三种很少使用)

HTTP方法说明作用
GET从服务器端获取数据,请求body在地址栏上获取资源
POST向服务器端提交数据,请求数据在报文body里;发送一个修改数据的请求,需求数据要重新新创建。用于创建子资源。创建、更新、删除、查询资源均可使用
PUT向服务器端提交数据,请求数据在报文body里;发送一个修改数据的请求,需求数据更新**(全部更新)**用于创建、更新资源
DELETE向服务器端提交数据,请求数据在报文body里;发送一个删除数据的请求删除资源
PATCH向服务器端提交数据,请求数据在报文body里;与PUT类似,发送一个修改数据的请求,区别在于PATCH代表部分更新;后来提出的接口方法,使用时可能去要验证客户端和服务端是否支持用于创建、更新资源(局部更新)

SpringbootWeb案例/分层解耦

分层:职责分离(每个层次只负责特定的职责)、降低耦合度(层次之间依赖关系更加清晰)

面向接口编程:便于扩展程序功能(新增一个新的接口实现类,扩展功能)

三层架构

  • Controller:控制层。接收前端发送的请求,对请求进行处理,并响应数据。
  • Service:业务逻辑层。处理具体的业务逻辑。
  • Dao:数据访问层(Data Access Object),也称为持久层。负责数据访问操作,包括数据的增、删、改、查。

案例注解

@ResponseBody:书写在Controller方法上或类上,方法的返回值会转换为Json数据直接响应给浏览器

@RestController:@ResponseBody + @Controller

注解说明位置
@Component声明bean的基础注解不属于以下三类时,用此注解
@Controller@Component的衍生注解标注在控制层类上
@Service@Component的衍生注解标注在业务层类上
@Mapper/@Repository@Component的衍生注解标注在数据访问层类上(由于与mybatis整合,用的少)

组件扫描

  • 前面声明bean的四大注解,要想生效,还需要被组件扫描注解 @ComponentScan 扫描。
  • 该注解虽然没有显式配置,但是实际上已经包含在了启动类声明注解 @SpringBootApplication 中,默认扫描的范围是启动类所在包及其子包。
Bean注入注解

@Autowired注解,默认是按照类型进行自动装配的(去IOC容器中找某个类型的对象,然后完成注入操作)

当spring容器中有两个相同类型的bean时

  • 使用@Primary注解:当存在多个相同类型的Bean注入时,加上@Primary注解,来确定默认的实现
  • 使用@Qualifier注解:指定当前要注入的bean对象。 在@Qualifier的value属性中,指定注入的bean的名称。 @Qualifier注解不能单独使用,必须配合@Autowired使用
  • 使用@Resource注解:按照bean的名称进行注入

@Autowird 与 @Resource的区别(面试题)

  • @Autowired 是spring框架提供的注解,而@Resource是JDK提供的注解
  • @Autowired 默认是按照类型注入,而@Resource是按照名称注入
依赖注入注解详解
@Service("beanName") // 指定bean注入名称为beanName
UserServiceImpl // 默认bean注入名称为userServiceImpl
    
@Autowird // 通过类型注入bean(多态形式)
private UserService userService;
- @Primary注解:多个相同类型的bean,在相同类型对象上添加注解即为增加优先级
- @Qualifier("userServiceImpl")注解:配合Autowird注解,指定名称注入

@Resource
private UserService userService;
- 先通过名称,再通过类型
- @Resource("beanName"):添加value属性则只会根据name找,找不到也会报错

案例代码

// 实体类:User、Result
// 分层解耦之前
@RequestMapping("/users")
public Result users() throws Exception {
    Reader r = new FileReader("springboot-web-demo\\src\\main\\resources\\user.txt");
    BufferedReader br = new BufferedReader(r);
    List<User> list = new ArrayList<>();
    String str;
    while((str = br.readLine()) != null){
        String[] split = str.split(",");
        User user = new User();
        user.setId(Integer.parseInt(split[0]));
        user.setName(split[1]);
        user.setTele(split[2]);
        user.setUsername(split[3]);
        user.setAge(Integer.parseInt(split[4]));
        user.setCreateTime(LocalDateTime.parse(split[5],DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")));
        list.add(user);
    }
    System.out.println("users()");
    br.close();
    r.close();
    return Result.success(list);
}

// 分层解耦之后
@RestController
public class UserController {
    @Autowired
    private UserService userService;
    @RequestMapping("/list")
    public Result list() throws Exception {
        return Result.success(this.userService.getUserList());
    }
}
@Service
public class UserServiceImpl implements UserService {
    @Autowired
    private UserDao userDao;
    @Override
    public List<User> getUserList() throws FileNotFoundException {
        List<String> userLines = this.userDao.getUserLines();
        List<User> list = userLines.stream().map(line -> {
            User user = new User();
            String[] str = line.split(",");
            user.setId(Integer.parseInt(str[0]));
            user.setName(str[1]);
            user.setTele(str[2]);
            user.setUsername(str[3]);
            user.setAge(Integer.parseInt(str[4]));
            user.setCreateTime(LocalDateTime.parse(str[5], DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")));
            return user;
        }).toList();
        return list;
    }
}
// txt中多行User数据(1,daqiao,1234567890,大乔,22,2024-07-15 15:05:45)
@Component
public class UserDaoImpl implements UserDao {
    @Override
    public List<String> getUserLines() throws FileNotFoundException {
        InputStream is = new FileInputStream("springboot-web-demo\\src\\main\\resources\\user.txt");
        List<String> lines = IoUtil.readLines(is, "UTF-8", new ArrayList<>());
        // IoUtil.readLines来自于cn.hutool工具类依赖
        return lines;
    }
}

Spring中的两个核心概念

控制反转: Inversion Of Control,简称IOC。对象的创建控制权由程序自身转移到外部(容器),这种思想称为控制反转。

  • 对象的创建权由程序员主动创建转移到容器(由容器创建、管理对象)。这个容器称为:IOC容器或Spring容器。

依赖注入: Dependency Injection,简称DI。容器为应用程序提供运行时,所依赖的资源,称之为依赖注入。

  • 程序运行时需要某个资源,此时容器就为其提供这个资源。
  • 例:EmpController程序运行时需要EmpService对象,Spring容器就为其提供并注入EmpService对象。

bean对象:IOC容器中创建、管理的对象,称之为:bean对象。