Web后端开发入门

Web后端开发入门

一、SpringBootWeb入门

  • 创建springboot工程,vscode中 ctrl+shift+p 搜索spring initializr create a Maven project

  • vscode创建的项目中,pom.xml默认没有父工程,可自行添加;如果不需要连接数据库,则依赖中暂时不要引入数据库相关依赖,否则运行项目会报错。

    xml 复制代码
    <?xml version="1.0" encoding="UTF-8"?>
    <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
        xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
        <modelVersion>4.0.0</modelVersion>
        <groupId>com.zcn</groupId>
        <artifactId>springboot-web-quickstart</artifactId>
        <version>0.0.1-SNAPSHOT</version>
        <name>springboot-web-quickstart</name>
        <description>Demo project for Spring Boot</description>
    
        <!-- 父工程 -->
        <parent>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-parent</artifactId>
            <version>2.7.6</version>
            <relativePath/> <!-- lookup parent from repository -->
        </parent>
    
    
    
    
        <properties>
            <java.version>1.8</java.version>
            <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
            <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
            <spring-boot.version>2.7.6</spring-boot.version>
        </properties>
    
        <dependencies>
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-starter-web</artifactId>
            </dependency>
    
            <!-- <dependency>
                <groupId>org.mybatis.spring.boot</groupId>
                <artifactId>mybatis-spring-boot-starter</artifactId>
                <version>2.3.0</version>
            </dependency> -->
    
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-devtools</artifactId>
                <scope>runtime</scope>
                <optional>true</optional>
            </dependency>
    
            <!-- <dependency>
                <groupId>com.mysql</groupId>
                <artifactId>mysql-connector-j</artifactId>
                <scope>runtime</scope>
            </dependency> -->
    
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-configuration-processor</artifactId>
                <optional>true</optional>
            </dependency>
    
            <dependency>
                <groupId>org.projectlombok</groupId>
                <artifactId>lombok</artifactId>
                <optional>true</optional>
            </dependency>
    
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-starter-test</artifactId>
                <scope>test</scope>
            </dependency>
        </dependencies>
        
        <dependencyManagement>
            <dependencies>
                <dependency>
                    <groupId>org.springframework.boot</groupId>
                    <artifactId>spring-boot-dependencies</artifactId>
                    <version>${spring-boot.version}</version>
                    <type>pom</type>
                    <scope>import</scope>
                </dependency>
            </dependencies>
        </dependencyManagement>
    
        <build>
            <plugins>
                <plugin>
                    <groupId>org.apache.maven.plugins</groupId>
                    <artifactId>maven-compiler-plugin</artifactId>
                    <version>3.8.1</version>
                    <configuration>
                        <source>1.8</source>
                        <target>1.8</target>
                        <encoding>UTF-8</encoding>
                    </configuration>
                </plugin>
                <plugin>
                    <groupId>org.springframework.boot</groupId>
                    <artifactId>spring-boot-maven-plugin</artifactId>
                    <version>${spring-boot.version}</version>
                    <configuration>
                        <mainClass>com.zcn.SpringbootWebQuickstartApplication</mainClass>
                        <skip>true</skip>
                    </configuration>
                    <executions>
                        <execution>
                            <id>repackage</id>
                            <goals>
                                <goal>repackage</goal>
                            </goals>
                        </execution>
                    </executions>
                </plugin>
            </plugins>
        </build>
    
    </project>
  • 定义HelloController类,添加方法 hello,并添加注解

    java 复制代码
    package com.zcn.controller;
    
    import org.springframework.web.bind.annotation.RestController;
    import org.springframework.web.bind.annotation.RequestMapping;
    
    // 请求处理类
    @RestController
    public class HelloController {
        @RequestMapping("/hello")
        public String hello() {
            System.out.println("hello world");
            return "Hello World";
        }
    }
    java 复制代码
    package com.zcn;
    
    import org.springframework.boot.SpringApplication;
    import org.springframework.boot.autoconfigure.SpringBootApplication;
    
    @SpringBootApplication
    public class SpringbootWebQuickstartApplication {
        public static void main(String[] args) {
            SpringApplication.run(SpringbootWebQuickstartApplication.class, args);
        }
    }

二、HTTP协议

  • 概念:Hyper Text Transfer Protocol,超文本传输协议,规定了浏览器和服务器之间数据传输的规则。
  • 特点:
    1. 基于TCP协议:面向连接,安全
    2. 基于请求-响应模型的:一次请求对应一次响应
    3. HTTP协议是无状态的协议:对于事务处理没有记忆能力。每次请求-响应都是独立的。
      • 缺点:多次请求间不能共享数据
      • 优点:速度快

2.1 HTTP 请求数据格式

2.2 HTTP请求响应格式

  • 状态码大类
状态码分类 说明
1xx 响应中------临时状态码,表示请求已经接受,告诉客户端应该继续请求或者如果它已经完成则忽略它
2xx 成功------表示请求已经被成功接收,处理已完成
3xx 重定向------重定向到其它地方:它让客户端再发起一个请求以完成整个处理。
4xx 客户端错误------处理发生错误,责任在客户端,如:客户端的请求一个不存在的资源,客户端未被授权,禁止访问等
5xx 服务器端错误------处理发生错误,责任在服务端,如:服务端抛出异常,路由出错,HTTP版本不支持等
  • 常见的响应状态码
状态码 英文描述 解释
200 OK 客户端请求成功,即处理成功,这是我们最想看到的状态码
302 Found 指示所请求的资源已移动到由Location响应头给定的 URL,浏览器会自动重新访问到这个页面
304 Not Modified 告诉客户端,你请求的资源至上次取得后,服务端并未更改,你直接用你本地缓存吧。隐式重定向
400 Bad Request 客户端请求有语法错误,不能被服务器所理解
403 Forbidden 服务器收到请求,但是拒绝提供服务,比如:没有权限访问相关资源
404 Not Found 请求资源不存在,一般是URL输入有误,或者网站资源被删除了
405 Method Not Allowed 请求方式有误,比如应该用GET请求方式的资源,用了POST
428 Precondition Required 服务器要求有条件的请求,告诉客户端要想访问该资源,必须携带特定的请求头
429 Too Many Requests 指示用户在给定时间内发送了太多请求("限速"),配合 Retry-After(多长时间后可以请求)响应头一起使用
431 Request Header Fields Too Large 请求头太大,服务器不愿意处理请求,因为它的头部字段太大。请求可以在减少请求头域的大小后重新提交。
500 Internal Server Error 服务器发生不可预期的错误。服务器出异常了,赶紧看日志去吧
503 Service Unavailable 服务器尚未准备好处理请求,服务器刚刚启动,还未初始化好

2.3 HTTP协议解析

java 复制代码
package com.itheima;

import java.io.*;
import java.net.ServerSocket;
import java.net.Socket;
import java.nio.charset.StandardCharsets;

/*
 * 自定义web服务器
 */
public class Server {
    public static void main(String[] args) throws IOException {
        ServerSocket ss = new ServerSocket(8080); // 监听指定端口
        System.out.println("server is running...");

        while (true){
            Socket sock = ss.accept();
            System.out.println("connected from " + sock.getRemoteSocketAddress());

            //开启线程处理请求
            Thread t = new Handler(sock);
            t.start();
        }
    }
}

class Handler extends Thread {
    Socket sock;

    public Handler(Socket sock) {
        this.sock = sock;
    }

    public void run() {
        try (InputStream input = this.sock.getInputStream(); OutputStream output = this.sock.getOutputStream()) {
                handle(input, output);
        } catch (Exception e) {
            try {
                this.sock.close();
            } catch (IOException ioe) {
            }
            System.out.println("client disconnected.");
        }
    }

    private void handle(InputStream input, OutputStream output) throws IOException {
        BufferedReader reader = new BufferedReader(new InputStreamReader(input, StandardCharsets.UTF_8));
        BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(output, StandardCharsets.UTF_8));

        // 读取HTTP请求:
        boolean requestOk = false;
        String first = reader.readLine();
        if (first.startsWith("GET / HTTP/1.")) {
            requestOk = true;
        }

        for (;;) {
            String header = reader.readLine();
            if (header.isEmpty()) { // 读取到空行时, HTTP Header读取完毕
                break;
            }
            System.out.println(header);
        }
        System.out.println(requestOk ? "Response OK" : "Response Error");

        if (!requestOk) {// 发送错误响应:
            writer.write("HTTP/1.0 404 Not Found\r\n");
            writer.write("Content-Length: 0\r\n");
            writer.write("\r\n");
            writer.flush();
        } else {  // 发送成功响应:
            //读取html文件,转换为字符串
            InputStream is = Server.class.getClassLoader().getResourceAsStream("html/a.html");
            BufferedReader br = new BufferedReader(new InputStreamReader(is));
            StringBuilder data = new StringBuilder();
            String line = null;
            while ((line = br.readLine()) != null){
                data.append(line);
            }
            br.close();
            int length = data.toString().getBytes(StandardCharsets.UTF_8).length;

            writer.write("HTTP/1.1 200 OK\r\n");
            writer.write("Connection: keep-alive\r\n");
            writer.write("Content-Type: text/html\r\n");
            writer.write("Content-Length: " + length + "\r\n");
            writer.write("\r\n"); // 空行标识Header和Body的分隔
            writer.write(data.toString());
            writer.flush();
        }
    }
}
html 复制代码
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="utf8">
    <title>Title</title>
</head>
<body>

<table border="1" cellspacing="0" width="500">
    <tr>
        <th>序号</th>
        <th>品牌名称</th>
        <th>企业名称</th>

    </tr>
    <tr align="center">
        <td>010</td>
        <td>三只松鼠</td>
        <td>三只松鼠</td>
    </tr>

    <tr align="center">
        <td>009</td>
        <td>优衣库</td>
        <td>优衣库</td>
    </tr>

    <tr align="center">
        <td>008</td>
        <td>小米</td>
        <td>小米科技有限公司</td>
    </tr>


</table>


</body>
</html>

三、Tomcat介绍和使用

  • 概念: Tomcat是Apache 软件基金会一个核心项目,是一个开源免费的轻量级Web服务器,支持Servlet/JSP少量JavaEE规范。
  • JavaEE:Java Enterprise Edition,Java企业版。指Java企业级开发的技术规范总和。包含13项技术规范:JDBC、JNDI、EJB、RMI、JSP、Servlet、XML、JMS、Java IDL、JTS、JTA、JavaMail、JAF
  • Tomcat 也被称为 Web容器、Servlet容器。Servlet程序需要依赖于 Tomcat才能运行
  • 官网:https://tomcat.apache.org

Tomcat基本使用

步骤:

  1. 官网下载压缩包并解压至提前准备好的目录(不含中文)
  2. 双击文件夹中的bin/startup.bat即可
  3. 卸载只需要将整个文件夹删除即可
  • 若出现乱码,修改conf/logging.properties,将UTF-8改成GBK
  1. 关闭,Crtl+C
  • 启动Tomcat后,在网页中进入localhost:8080即可进入Tomcat主页

修改Tomcat端口号

  • 在server.xml进行修改

    xml 复制代码
    <Connector port="8080" protocol="HTTP/1.1"
               connectionTimeout="20000"
               redirectPort="8443" />
    • 注意事项:HTTP协议默认端口号为80,如果Tomcat将端口号改为80,则将来访问Tomcat时将不用输入端口号

部署

  • 将开发好的应用复制到webapps目录下即可

四、请求响应

4.1 概述:

  • 请求(HttpServletRequest):获取请求数据
  • 响应(HttpServletResponse):设置响应数据
  • BS架构:Browser/Server,浏览器/服务器架构模式,客户端只需要浏览器,应用程序的逻辑和数据都存储在服务端。(维护方便,但体验一般)
  • CS架构:Client/Server,客户端/服务器架构模式。(开发、维护麻烦,但体验不错)

4.2 postman工具

  • Postman是一款功能强大的网页调试与发送网页HTTP请求的Chrome插件。常用于进行接口测试。

  • 使用方式:输入网址即可进行测试

4.3 简单参数

  • 原始方式:在原始的web程序中,获取请求参数,需要通过HttpServletRequest 对象手动获取。

    java 复制代码
    @RequestMapping("/simpleParam")
    public String simpleParam(HttpServletRequest request){
        //获取请求参数
        String name = request.getParameter("name");
        String ageStr = request.getParameter("age");
    
        int age = Integer.parseInt(ageStr);
        System.out.println(name+ ":" + age);
        return "OK";
    }
    • 在postman中输入地址,使用GET方式:

      http 复制代码
      http://localhost:8080/simpleParam?name=Tom&age=10
  • springboot方式接收:

    java 复制代码
    @RequestMapping("/simpleParam")
    public String simpleParam(String name, Integer age){
       System.out.println(name+ ":" + age);
       return "OK";
    }
  • 如果方法形参名称与请求参数名称不匹配,可以使用 @RequestParam 完成映射。

    java 复制代码
    @RequestMapping("/simpleParam")
    public String simpleParam(@RequestParam(name = "name", required = false) String username, Integer age){
        System.out.println(username+ ":" + age);
        return "OK";
    }
  • @RequestParam中的required属性默认为true,代表该请求参数必须传递,如果不传递将报错。 如果该参数是可选的,可以将required属性设置为false。

4.4 实体参数

简单实体对象:请求参数名与形参对象属性名相同,定义POJO接收即可

java 复制代码
// 将参数封装进user中
@RequestMapping("/simplePojo")
public String simplePojo(User user){
    System.out.println(user);
    return "OK";
}
java 复制代码
package com.itheima.pojo;

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 +
                '}';
    }
}

复杂实体对象:请求参数名与形参对象属性名相同,按照对象层次结构关系即可接收嵌套POJO属性参数。

java 复制代码
@RequestMapping("/complexPojo")
public String complexPojo(User user){
    System.out.println(user);
    return "OK";
}
java 复制代码
package com.itheima.pojo;

public class Address {
    private String province;
    private String city;

    @Override
    public String toString() {
        return "Address{" +
                "province='" + province + '\'' +
                ", city='" + 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;
    }
}
java 复制代码
package com.itheima.pojo;

public class User {
    private String name;
    private Integer age;
	
    // 将address封装进来
    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 +
                '}';
    }
}

数组集合参数

java 复制代码
//3. 数组集合参数
@RequestMapping("/arrayParam")
public String arrayParam(String[] hobby){
    System.out.println(Arrays.toString(hobby));
    return "OK";
}

@RequestMapping("/listParam")
public String listParam(@RequestParam List<String> hobby){
    System.out.println(hobby);
    return "OK";
}
  • 数组参数:请求参数名与形参数组名称相同且请求参数为多个,定义数组类型形参即可接收参数。
  • 集合参数:请求参数名与形参集合名称相同且请求参数为多个,使用@RequestParam 绑定参数关系。

日期参数:使用 @DateTimeFormat 注解完成日期参数格式转换

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

Json参数:JSON数据键名与形参对象属性名相同,定义POJO类型形参即可接收参数,需要使用 @RequestBody 标识

java 复制代码
//5. json参数
@RequestMapping("/jsonParam")
public String jsonParam(@RequestBody User user){
    System.out.println(user);
    return "OK";
}

路径参数:通过请求URL直接传递参数,使用{...}来标识该路径参数,需要使用 @PathVariable 获取路径参数

java 复制代码
//6. 路径参数
@RequestMapping("/path/{id}")
public String pathParam(@PathVariable Integer id){
    System.out.println(id);
    return "OK";
}

@RequestMapping("/path/{id}/{name}")
public String pathParam2(@PathVariable Integer id , @PathVariable String name){
    System.out.println(id);
    System.out.println(name);
    return "OK";
}

4.5 响应数据

  • 需要统一响应结果:

    java 复制代码
    public class Result {
        //响应码,1 代表成功; 0 代表失败
        private Integer code;
        //提示信息
        private String msg;
        //返回的数据
        private Object data; 
        //......
    }
    java 复制代码
    package com.itheima.pojo;
    
    /**
     * 统一响应结果封装类
     */
    public class Result {
        private Integer code ;//1 成功 , 0 失败
        private String msg; //提示信息
        private Object data; //数据 date
    
        public Result() {
        }
        public Result(Integer code, String msg, Object data) {
            this.code = code;
            this.msg = msg;
            this.data = data;
        }
        public Integer getCode() {
            return code;
        }
        public void setCode(Integer code) {
            this.code = code;
        }
        public String getMsg() {
            return msg;
        }
        public void setMsg(String msg) {
            this.msg = msg;
        }
        public Object getData() {
            return data;
        }
        public void setData(Object data) {
            this.data = data;
        }
    
        public static Result success(Object data){
            return new Result(1, "success", data);
        }
        public static Result success(){
            return new Result(1, "success", null);
        }
        public static Result error(String msg){
            return new Result(0, msg, null);
        }
    
        @Override
        public String toString() {
            return "Result{" +
                    "code=" + code +
                    ", msg='" + msg + '\'' +
                    ", data=" + data +
                    '}';
        }
    }
    java 复制代码
    // 响应数据
    @RequestMapping("/hello")
    public Result hello(){
        System.out.println("Hello World ~");
        //return new Result(1,"success","Hello World ~");
        return Result.success("Hello World ~");
    }
    
    @RequestMapping("/getAddr")
    public Result getAddr(){
        Address addr = new Address();
        addr.setProvince("广东");
        addr.setCity("深圳");
        return Result.success(addr);
    }
    
    @RequestMapping("/listAddr")
    public Result listAddr(){
        List<Address> list = new ArrayList<>();
    
        Address addr = new Address();
        addr.setProvince("广东");
        addr.setCity("深圳");
    
        Address addr2 = new Address();
        addr2.setProvince("陕西");
        addr2.setCity("西安");
    
        list.add(addr);
        list.add(addr2);
        return Result.success(list);
    }

五、分层解耦

5.1 三层架构(springboot-web-req-resp代码文件)

  1. controller:控制层,接收前端发送的请求,对请求进行处理,并响应数据。
  2. service:业务逻辑层,处理具体的业务逻辑。
  3. dao:数据访问层(Data Access Object)(持久层),负责数据访问操作,包括数据的增、删、改、查。
  • 步骤:

    1. 分装数据访问层DAO:

      • 在包中创建dao文件夹,首先创建EmpDao.java接口文件,用于定义对数据进行的操作。

        java 复制代码
        package com.itheima.dao;
        
        import java.util.List;
        
        import com.itheima.pojo.Emp;
        
        public interface EmpDao {
            public List<Emp> listEmp();
        }
      • 其次创建impl.EmpDaoA.java实现类文件,用于读取emp.xml文件,将数据进行解析。

        java 复制代码
        package com.itheima.dao.impl;
        
        import java.util.List;
        
        import com.itheima.dao.EmpDao;
        import com.itheima.pojo.Emp;
        import com.itheima.utils.XmlParserUtils;
        
        public class EmpDaoA implements EmpDao { // 类声明,为EmpDao接口的实现类
            @Override
            public List<Emp> listEmp() { // 重写接口中的方法
                // 加载并解析emp.xml
                String file = this.getClass().getClassLoader().getResource("emp.xml").getFile();
                System.out.println(file);
                List<Emp> emplist = XmlParserUtils.parse(file, Emp.class); // 调用parse方法,将Emp中的对象放入 List<Emp>中
                return emplist; // 将结果返回给service层
            }
        }
    2. 业务逻辑层Service

      • 同理,创建两个文件,接口文件和实现类文件

        java 复制代码
        package com.itheima.service;
        
        import java.util.List;
        
        import com.itheima.pojo.Emp;
        
        public interface EmpService {
            public List<Emp> listEmp();
        }
        java 复制代码
        package com.itheima.service.impl;
        
        import java.util.List;
        
        import com.itheima.dao.EmpDao;
        import com.itheima.dao.impl.EmpDaoA;
        import com.itheima.pojo.Emp;
        import com.itheima.service.EmpService;
        
        public class EmpServiceA implements EmpService {
        
            private EmpDao empDao = new EmpDaoA();
        
            @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;
            }
        }
    3. 控制层control:调用service层,接收请求,返回一个json格式

      java 复制代码
      package com.itheima.controller;
      
      import com.itheima.pojo.Emp;
      import com.itheima.pojo.Result;
      import com.itheima.service.EmpService;
      import com.itheima.service.impl.EmpServiceA;
      import org.springframework.web.bind.annotation.RequestMapping;
      import org.springframework.web.bind.annotation.RestController;
      import java.util.List;
      
      @RestController
      public class EmpController {
      
          private EmpService empService = new EmpServiceA();
      
          @RequestMapping("/listEmp") // 控制层类
          public Result list() {
              // 3. 响应数据
              List<Emp> empList = empService.listEmp();
              return Result.success(empList);
          }
      }

5.2 IOC-DI

  • 控制反转: Inversion Of Control,简称IOC。对象的创建控制权由程序自身转移到外部(容器),这种思想称为控制反转。
  • 依赖注入: Dependency Injection,简称DI。容器为应用程序提供运行时,所依赖的资源,称之为依赖注入。
  • **Bean对象:**IOC容器中创建、管理的对象,称之为bean。
java 复制代码
@Autowired // 运行时,IOC容器会提供该类型的bean对象,并赋值给该变量 也称为依赖注入。
private EmpService empService;

/*
不再给变量赋值,而使用@Autowired注解,让其自动寻找IOC容器中的对象
*/
java 复制代码
@Component // 将当前类交给IOC管理,成为IOC容器中的bean
public class EmpServiceA implements EmpService {

    @Autowired // 运行时,IOC容器会提供该类型的bean对象,并赋值给该变量 也称为依赖注入。
    private EmpDao empDao;
    ......
}
/*
使用@Component,让实现类放在容器中
*/
  • 如果想用不同的实现类,将@Component注释,即将该实现类移出IOC容器中,即可实现解耦

IOC详解

  • 在实际项目中常用衍生注解,衍生注解中都包含了@Component

  • 可以对bean的名字进行重命名

    java 复制代码
    @Repository("daoA")
    // 在VScode中,@Repository不在Bean中显示
  • 注意事项:

    • 声明bean的时候,可以通过value属性指定bean的名字,如果没有指定,默认为类名首字母小写。
    • 使用以上四个注解都可以声明bean,但是在springboot集成web开发中,声明控制器bean只能用@Controller。

Bean组件扫描

  • 前面声明bean的四大注解,要想生效,还需要被组件扫描注解@ComponentScan扫描。

  • @ComponentScan注解虽然没有显式配置,但是实际上已经包含在了启动类声明注解 @SpringBootApplication 中,默认扫描的范围是启动类所在包及其子包。

  • 想要让包外的子包被扫描,在主程序中修改:

    java 复制代码
    // @ComponentScan({"dao","com.itheima"}) // 不推荐该方式
    
    @SpringBootApplication
    public class SpringbootWebReqRespApplication {
    
        public static void main(String[] args) {
            SpringApplication.run(SpringbootWebReqRespApplication.class, args);
        }
    
    }
    // 最佳方式是把子包放在包内

DI详解

  • @Autowired注解,默认是按照类型进行,如果存在多个相同类型的bean,将会报出如下错误:

    cmd 复制代码
    Field empService in com.itheima.controller.EmpController required a single bean, but 2 were found:
    	- empServiceA:...
    	- empServiceB:...
  • 通过以下方式生效:

    java 复制代码
    @Primary  // 在类上加入@Primary注解
    @Service
    public class EmpServiceA implements EmpService {
    }
    java 复制代码
    @RestController
    public class EmpController {
        @Autowired
        @Qualifier("empServiceA") // 指定bean名称
        private EmpService empService ;
    }
    java 复制代码
    @RestController
    public class EmpController {
        @Resource(name = "empServiceB") // 指定bean名称
        private EmpService empService ;
    }
  • @Resource与@Autowired区别:

    • @Autowired 是spring框架提供的注解,而@Resource是JDK提供的注解。

    • @Autowired 默认是按照类型注入,而@Resource默认是按照名称注入。

      public static void main(String[] args) {

      SpringApplication.run(SpringbootWebReqRespApplication.class, args);

      }

    }

    // 最佳方式是把子包放在包内

    复制代码

DI详解

  • @Autowired注解,默认是按照类型进行,如果存在多个相同类型的bean,将会报出如下错误:

    cmd 复制代码
    Field empService in com.itheima.controller.EmpController required a single bean, but 2 were found:
    	- empServiceA:...
    	- empServiceB:...
  • 通过以下方式生效:

    java 复制代码
    @Primary  // 在类上加入@Primary注解
    @Service
    public class EmpServiceA implements EmpService {
    }
    java 复制代码
    @RestController
    public class EmpController {
        @Autowired
        @Qualifier("empServiceA") // 指定bean名称
        private EmpService empService ;
    }
    java 复制代码
    @RestController
    public class EmpController {
        @Resource(name = "empServiceB") // 指定bean名称
        private EmpService empService ;
    }
  • @Resource与@Autowired区别:

    • @Autowired 是spring框架提供的注解,而@Resource是JDK提供的注解。
    • @Autowired 默认是按照类型注入,而@Resource默认是按照名称注入。
相关推荐
哈哈哈笑什么26 分钟前
分布式高并发Springcloud系统下的数据图同步断点续传方案【订单/商品/用户等】
分布式·后端·spring cloud
电饭叔28 分钟前
《python语言程序设计》2018版--第8章14题利用字符串输入作为一个信用卡号之一(Luhn算法解释)
android·java·python
Z3r4y31 分钟前
【代码审计】JeecgBoot-3.5.0 四处安全问题分析
java·web安全·代码审计·jeecg-boot
wangmengxxw32 分钟前
微服务-服务配置
java·运维·微服务·云计算·服务配置
桃花键仙41 分钟前
vLLM-ascend快速上手:从零到一部署Llama2推理服务
后端
桃花键仙42 分钟前
PyTorch模型迁移昇腾平台全流程:ResNet50实战指南
后端
1024肥宅43 分钟前
告别异地登录告警!用 GitHub Self-Hosted Runner 打造“零打扰”全栈自动化部署
前端·后端·github
猪猪拆迁队1 小时前
高性能 Package构建系统设计与实现
前端·后端·node.js
_院长大人_1 小时前
Spring Boot 客户端设计示例:自动刷新 Token 并重试接口调用(Springboot Starter 封装)
java·spring boot·后端