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,并添加注解
javapackage 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"; } }javapackage 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,超文本传输协议,规定了浏览器和服务器之间数据传输的规则。

- 特点:
- 基于TCP协议:面向连接,安全
- 基于请求-响应模型的:一次请求对应一次响应
- 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基本使用
步骤:
- 官网下载压缩包并解压至提前准备好的目录(不含中文)
- 双击文件夹中的bin/startup.bat即可
- 卸载只需要将整个文件夹删除即可
- 若出现乱码,修改conf/logging.properties,将UTF-8改成GBK
- 关闭,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方式:
httphttp://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 响应数据

-
需要统一响应结果:
javapublic class Result { //响应码,1 代表成功; 0 代表失败 private Integer code; //提示信息 private String msg; //返回的数据 private Object data; //...... }javapackage 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代码文件)
- controller:控制层,接收前端发送的请求,对请求进行处理,并响应数据。
- service:业务逻辑层,处理具体的业务逻辑。
- dao:数据访问层(Data Access Object)(持久层),负责数据访问操作,包括数据的增、删、改、查。

-
步骤:
-
分装数据访问层DAO:
-
在包中创建dao文件夹,首先创建EmpDao.java接口文件,用于定义对数据进行的操作。
javapackage com.itheima.dao; import java.util.List; import com.itheima.pojo.Emp; public interface EmpDao { public List<Emp> listEmp(); } -
其次创建impl.EmpDaoA.java实现类文件,用于读取emp.xml文件,将数据进行解析。
javapackage 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层 } }
-
-
业务逻辑层Service
-
同理,创建两个文件,接口文件和实现类文件
javapackage com.itheima.service; import java.util.List; import com.itheima.pojo.Emp; public interface EmpService { public List<Emp> listEmp(); }javapackage 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; } }
-
-
控制层control:调用service层,接收请求,返回一个json格式
javapackage 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,将会报出如下错误:
cmdField 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,将会报出如下错误:
cmdField 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默认是按照名称注入。