先通过一个小练习简单了解以下SpringBootWeb。
小练习:
需求:使用SpringBoot开发一个Web应用,浏览器发起请求/hello后,给浏览器返回字符串"Hello World~"。
步骤:
1.创建SpringBoot项目,勾选Web相关依赖
2.编写HelloController类,添加方法Hello,并添加注解
代码演示:
@RestController
public class HelloController {
@RequestMapping("/hello")
public String HelloController() {
System.out.println("Hello World~");
return "Hello World~";
}
}
3.运行SpringBoot的启动类(创建完SpringBoot项目后自动创建,不用自己创建)
代码演示:
@SpringBootApplication
public class SpringbootWebQuickstartApplication {
public static void main(String[] args) {
SpringApplication.run(SpringbootWebQuickstartApplication.class, args);
}
}
运行结果:
(注意:右下角红色框选部分为端口号)
4.打开浏览器输入网址localhost:8080(端口号)/hello
运行结果:
起步依赖:
内嵌Tomcat服务器:
Tomcat:
官方网站:Apache Tomcat® - Welcome!
基本使用:
·部署:应用复制到webapps目录。
请求响应:
请求:
接口测试工具Postman:
接受方法
简单参数接收:
方法:
方法1只需要简单了解,下面我对方法2,3做一下代码演示
方法2代码演示:
@RestController
public class SimpleParam1 {
@RequestMapping("/simpleParam1")
public String SimpleParam(String name, int age) {
System.out.println(name + ":" + age);
return "OK";
}
}
Postman测试+下方运行结果:
运行结果:
方法3代码演示:
@RestController
public class SimpleParam2 {
@RequestMapping("/simpleParam2")
public String SimpleParam(@RequestParam(name = "name",required = false) String username, int age) {
System.out.println(username + ":" + age);
return "OK";
}
}
Postman测试+下方运行结果:
不传递name:
运行结果:
实体参数接收:
简单实体对象:
代码演示:
User类:
public class User {
private String name;
private int age;
public User() {
}
public User(String name, int age) {
this.name = name;
this.age = age;
}
/**
* 获取
* @return name
*/
public String getName() {
return name;
}
/**
* 设置
* @param name
*/
public void setName(String name) {
this.name = name;
}
/**
* 获取
* @return age
*/
public int getAge() {
return age;
}
/**
* 设置
* @param age
*/
public void setAge(int age) {
this.age = age;
}
public String toString() {
return "User{name = " + name + ", age = " + age + "}";
}
}
等待处理类:
@RestController
public class SimplePojo {
@RequestMapping("/simplePojo")
public String simplePojo(User user) {
System.out.println(user);
return "OK";
}
}
Postman测试:
运行结果:
复杂实体对象:
代码演示:
User类:
package com.han.springbootwebquickstart.pojo;
public class User {
private String name;
private int age;
private Address address;
public User() {
}
public User(String name, int age, Address address) {
this.name = name;
this.age = age;
this.address = address;
}
/**
* 获取
* @return name
*/
public String getName() {
return name;
}
/**
* 设置
* @param name
*/
public void setName(String name) {
this.name = name;
}
/**
* 获取
* @return age
*/
public int getAge() {
return age;
}
/**
* 设置
* @param age
*/
public void setAge(int age) {
this.age = age;
}
/**
* 获取
* @return address
*/
public Address getAddress() {
return address;
}
/**
* 设置
* @param address
*/
public void setAddress(Address address) {
this.address = address;
}
public String toString() {
return "User{name = " + name + ", age = " + age + ", address = " + address + "}";
}
}
Address类:
public class Address {
private String province;
private String city;
public Address() {
}
public Address(String province, String city) {
this.province = province;
this.city = city;
}
/**
* 获取
* @return province
*/
public String getProvince() {
return province;
}
/**
* 设置
* @param province
*/
public void setProvince(String province) {
this.province = province;
}
/**
* 获取
* @return city
*/
public String getCity() {
return city;
}
/**
* 设置
* @param city
*/
public void setCity(String city) {
this.city = city;
}
public String toString() {
return "Address{province = " + province + ", city = " + city + "}";
}
}
等待处理类:
@RestController
public class ComplexPojo {
@RequestMapping("/complexPojo")
public String complexPojo(User user) {
System.out.println(user);
return "OK";
}
}
Postman测试:
运行结果:
数组集合参数接收
1.数组参数
代码演示:
@RequestMapping("/arrayParam")
public String arrayParam(String[] hobby) {
System.out.println(Arrays.toString(hobby));
return "OK";
}
Postman测试:
运行结果:
2.集合参数
请求参数名与形参中集合变量名相同,通过@RequestParam绑定参数关系。
代码演示:
@RequestMapping("/listParam")
public String listParam(@RequestParam List<String> hobby) {
System.out.println(hobby);
return "OK";
}
Postman测试:
运行结果:
日期参数:
代码演示:
@RequestMapping("/timeParam")
public String timeParam(@DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss") LocalDateTime updateTime) {
System.out.println(updateTime);
return "OK";
}
Postman测试:
运行结果:
json参数:
代码演示:
@RequestMapping("/jsonParam")
public String jsonParam(@RequestBody User user) {
System.out.println(user);
return "OK";
}
Postman测试:
运行结果:
路径参数:
代码演示:
@RequestMapping("/path/{id}/{name}")
public String pathParam(@PathVariable Integer id, @PathVariable String name) {
System.out.println(id + ":" + name);
return "OK";
}
Postman测试:
运行结果:
响应:
代码演示:
@RestController
public class ResponseController {
//返回字符串
@RequestMapping("/stringResponse")
public String stringResponse() {
return "Hello World";
}
//返回对象
@RequestMapping("/pojoResponse")
public Address pojoResponse() {
return new Address("hebei","shijiazhuang");
}
//返回集合
@RequestMapping("/listResponse")
public List<Address> listResponse() {
List<Address> list = new ArrayList<Address>();
Address address1 = new Address("hebei","shijiazhuang");
list.add(address1);
Address address2 = new Address("tianjin","tianjin");
list.add(address2);
return list;
}
}
Postman测试结果:
返回字符串
返回对象:
返回集合:
但是这种情况返回的数据过于多样化,不便于前端人员处理,所以为了规范化,一般采取创建Result对象来统一响应结果。
统一响应结果:
代码演示:
Result类:
public class Result {
private Integer code ;//1 成功 , 0 失败
private String msg; //提示信息
private Object data; //数据 data
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 +
'}';
}
}
Controller类:
@RestController
public class ResponseController {
//返回字符串
@RequestMapping("/stringResponse")
public Result stringResponse() {
return Result.success("Hello World");
}
//返回对象
@RequestMapping("/pojoResponse")
public Result pojoResponse() {
return Result.success(new Address("hebei","shijiazhuang"));
}
//返回集合
@RequestMapping("/listResponse")
public Result listResponse() {
List<Address> list = new ArrayList<Address>();
Address address1 = new Address("hebei","shijiazhuang");
list.add(address1);
Address address2 = new Address("tianjin","tianjin");
list.add(address2);
return Result.success(list);
}
}
Postman测试结果:
响应字符串:
响应对象:
响应集合:
案例:
加载并解析emp.xml文件中的数据,完成数据处理,并在页面展示
emp.xml:
<?xml version="1.0" encoding="UTF-8" ?>
<emps>
<emp>
<name>金毛狮王</name>
<age>55</age>
<image>https://web-framework.oss-cn-hangzhou.aliyuncs.com/web/1.jpg</image>
<!-- 1: 男, 2: 女 -->
<gender>1</gender>
<!-- 1: 讲师, 2: 班主任 , 3: 就业指导 -->
<job>1</job>
</emp>
<emp>
<name>白眉鹰王</name>
<age>65</age>
<image>https://web-framework.oss-cn-hangzhou.aliyuncs.com/web/2.jpg</image>
<gender>1</gender>
<job>1</job>
</emp>
<emp>
<name>青翼蝠王</name>
<age>45</age>
<image>https://web-framework.oss-cn-hangzhou.aliyuncs.com/web/3.jpg</image>
<gender>1</gender>
<job>2</job>
</emp>
<emp>
<name>紫衫龙王</name>
<age>38</age>
<image>https://web-framework.oss-cn-hangzhou.aliyuncs.com/web/4.jpg</image>
<gender>2</gender>
<job>3</job>
</emp>
</emps>
代码演示:
pom.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>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>3.3.0</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>com.han</groupId>
<artifactId>springboot-web-quickstart</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>springboot-web-quickstart</name>
<description>springboot-web-quickstart</description>
<properties>
<java.version>17</java.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.dom4j</groupId>
<artifactId>dom4j</artifactId>
<version>2.1.3</version>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
Emp类JavaBean:
public class Emp {
private String name;
private Integer age;
private String image;
private String gender;
private String job;
public Emp() {
}
public Emp(String name, Integer age, String image, String gender, String job) {
this.name = name;
this.age = age;
this.image = image;
this.gender = gender;
this.job = job;
}
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 String getImage() {
return image;
}
public void setImage(String image) {
this.image = image;
}
public String getGender() {
return gender;
}
public void setGender(String gender) {
this.gender = gender;
}
public String getJob() {
return job;
}
public void setJob(String job) {
this.job = job;
}
@Override
public String toString() {
return "Emp{" +
"name='" + name + '\'' +
", age=" + age +
", image='" + image + '\'' +
", gender='" + gender + '\'' +
", job='" + job + '\'' +
'}';
}
}
统一响应结果类Result:
public class Result {
private Integer code ;//1 成功 , 0 失败
private String msg; //提示信息
private Object data; //数据 data
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 +
'}';
}
}
Controller类EmpController:
@RestController
public class EmpController {
@RequestMapping("/listEmp")
public Result list(){
//1.加载emp.xml,并解析其中的数据
String file = this.getClass().getClassLoader().getResource("emp.xml").getFile();
List<Emp> empList = XmlParserUtils.parse(file, Emp.class);
//2.对员工信息中的gender、job进行修改
for (Emp emp : empList) {
//设置gender
String gender = emp.getGender();
if("1".equals(gender)){
emp.setGender("男");
} else if("2".equals(gender)){
emp.setGender("女");
}
//设置job
String job = emp.getJob();
if("1".equals(job)){
emp.setJob("讲师");
} else if("2".equals(job)){
emp.setJob("班主任");
} else if("3".equals(job)){
emp.setJob("就业指导");
}
}
//3.组装数据并返回
return Result.success(empList);
}
}
前端页面代码:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>员工信息</title>
</head>
<link rel="stylesheet" href="element-ui/index.css">
<script src="./js/vue.js"></script>
<script src="./element-ui/index.js"></script>
<script src="./js/axios-0.18.0.js"></script>
<body>
<h1 align="center">员工信息列表展示</h1>
<div id="app">
<el-table :data="tableData" style="width: 100%" stripe border >
<el-table-column prop="name" label="姓名" align="center" min-width="20%"></el-table-column>
<el-table-column prop="age" label="年龄" align="center" min-width="20%"></el-table-column>
<el-table-column label="图像" align="center" min-width="20%">
<template slot-scope="scope">
<el-image :src="scope.row.image" style="width: 80px; height: 50px;"></el-image>
</template>
</el-table-column>
<el-table-column prop="gender" label="性别" align="center" min-width="20%"></el-table-column>
<el-table-column prop="job" label="职位" align="center" min-width="20%"></el-table-column>
</el-table>
</div>
</body>
<style>
.el-table .warning-row {
background: oldlace;
}
.el-table .success-row {
background: #f0f9eb;
}
</style>
<script>
new Vue({
el: "#app",
data() {
return {
tableData: []
}
},
mounted(){
axios.get('/listEmp').then(res=>{
if(res.data.code){
this.tableData = res.data.data;
}
});
},
methods: {
}
});
</script>
</html>
Portman测试:
网页运行结果:
分层解耦:
Web开发的三层架构:
小练习:
将上述案例中的Controller代码分解成三层架构,代码如下
@RestController
public class EmpController {
@RequestMapping("/listEmp")
public Result list(){
//1.加载emp.xml,并解析其中的数据
String file = this.getClass().getClassLoader().getResource("emp.xml").getFile();
List<Emp> empList = XmlParserUtils.parse(file, Emp.class);
//2.对员工信息中的gender、job进行修改
for (Emp emp : empList) {
//设置gender
String gender = emp.getGender();
if("1".equals(gender)){
emp.setGender("男");
} else if("2".equals(gender)){
emp.setGender("女");
}
//设置job
String job = emp.getJob();
if("1".equals(job)){
emp.setJob("讲师");
} else if("2".equals(job)){
emp.setJob("班主任");
} else if("3".equals(job)){
emp.setJob("就业指导");
}
}
//3.组装数据并返回
return Result.success(empList);
}
}
代码演示:
Dao层:
接口:
public interface EmpDao {
public List<Emp> listEmp();
}
实现类:
public class EmpDaoA implements EmpDao {
@Override
public List<Emp> listEmp() {
String file = this.getClass().getClassLoader().getResource("emp.xml").getFile();
List<Emp> empList = XmlParserUtils.parse(file, Emp.class);
return empList;
}
}
Service层:
接口:
public interface EmpService {
public List<Emp> listEmp();
}
实现类:
public class EmpServiceA implements EmpService {
private EmpDao empDao = new EmpDaoA();
@Override
public List<Emp> listEmp() {
List<Emp> empList = empDao.listEmp();
for (Emp emp : empList) {
//设置gender
String gender = emp.getGender();
if("1".equals(gender)){
emp.setGender("男");
} else if("2".equals(gender)){
emp.setGender("女");
}
//设置job
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;
}
}
Controller层:
实现类:
@RestController
public class EmpController {
private EmpService empService = new EmpServiceA();
@RequestMapping("/listEmp")
public Result list(){
List<Emp> empList = empService.listEmp();
return Result.success(empList);
}
}
运行结果:
内聚和耦合:
我们就可以通过控制反转和依赖注入来分层解耦。
控制反转(IOC)和依赖注入(DI):
代码演示:
Dao层:
接口:
public interface EmpDao {
public List<Emp> listEmp();
}
实现类:
@Component
public class EmpDaoA implements EmpDao {
@Override
public List<Emp> listEmp() {
String file = this.getClass().getClassLoader().getResource("emp.xml").getFile();
List<Emp> empList = XmlParserUtils.parse(file, Emp.class);
return empList;
}
}
Service层:
接口:
public interface EmpService {
public List<Emp> listEmp();
}
实现类:
@Component
public class EmpServiceA implements EmpService {
@Autowired
private EmpDao empDao;
@Override
public List<Emp> listEmp() {
List<Emp> empList = empDao.listEmp();
for (Emp emp : empList) {
//设置gender
String gender = emp.getGender();
if("1".equals(gender)){
emp.setGender("男");
} else if("2".equals(gender)){
emp.setGender("女");
}
//设置job
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;
}
}
Controller层:
实现类:
@RestController
public class EmpController {
@Autowired
private EmpService empService ;
@RequestMapping("/listEmp")
public Result list(){
List<Emp> empList = empService.listEmp();
return Result.success(empList);
}
}
运行结果:
好处:
采用这种方式降低了层之间的耦合度,如果业务逻辑改变,要使用Service层中的其他实现类,那只需要编写好新的实现类后,在类上标注注解@Component,再修改原来使用的实现类的注解即可。
IOC细节:
Bean的声明:
目前主要使用的是下图中下面三个针对一个类的注解,Component一般只有在一个类不属于这三类的时候使用。
注意:
声明bean的时候,可以通过value属性指定bean的名字,如果没有指定,默认为类名首字母小写。
使用以上四个注解都可以声明bean,但是在springboot集成web开发中,声明控制器bean只能用@Controller。
Bean组件扫描:
DI细节:
Bean注入
★@Resource与@Autowired的区别
·@Autowired是spring框架提供的注解,而@Resource是JDK提供的注解
·@Autowired默认是按照类型注入,而@Resource默认是按照名称注入