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默认是按照名称注入。
相关推荐
字节跳动数据库6 分钟前
文章分享——相似函数处理方法
人工智能·后端·程序员
云技纵横7 分钟前
@Transactional 失效的 7 种场景:第 5 种最难排查
后端
用户67570498850224 分钟前
你知道 Go 结构体和结构体指针调用的区别吗?一文带你彻底搞懂!
后端·go
程序员cxuan40 分钟前
读懂 Claude Code 架构分析系列,第一篇,开始!
人工智能·后端·架构
用户67570498850244 分钟前
面试官问“装饰器模式”,这样回答薪资多要 3000!
后端
tntxia1 小时前
Geo Scene域名修改引起的一些问题
后端
用户298698530141 小时前
Java 实现 Word 文档加密与权限解除
java·后端
曲幽1 小时前
你的REST接口还在“过度投喂”数据吗?——FastAPI + GraphQL实战避坑指南
python·fastapi·web·graphql·route·cors·rest·strawberry
vanuan1 小时前
给你的A2A-Agent加把锁-认证鉴权实战指南
后端
Yeats_Liao1 小时前
14:Servlet中的页面跳转-Java Web
java·后端·架构