后端Web开发
Maven
Apache Maven 是一个项目管理和构建工具,它基于项目对象模型(POM)的概念,通过一小段描述信息来管理项目的构建。
Maven作用
依赖管理
统一的项目结构
项目构建
仓库
安装Maven
<mirror>
<id>alimaven</id>
<name>aliyun maven</name>
<url>http://maven.aliyun.com/nexus/content/groups/public/</url>
<mirrorOf>central</mirrorOf>
</mirror>
测试:
mvn -v
配置Maven环境
创建Maven项目
坐标
导入Maven项目
依赖配置
仓库网址:https://mvnrepository.com/
依赖传递
显示关系图
A的依赖关系图
B的依赖关系图
C的依赖关系图
排除依赖
依赖范围
生命周期
在同一套生命周期中,当运行后面的阶段时,前面的阶段都会运行,上图三套
SpringBoot
入门
入门代码
package com.itheima.controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
public class HelloController {
@RequestMapping("/Hello")
public String hello() {
System.out.println("Hello!!!");
return "Hello world!!!";
}
}
启动
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 |
服务器尚未准备好处理请求,服务器刚刚启动,还未初始化好 |
状态码大全:https://cloud.tencent.com/developer/chapter/13553
协议解析
Tomcat
基本使用
配置端口号:
部署:将文件移动到webapps文件夹下即可
https://docs.spring.io/spring-boot/docs/2.7.4/reference/htmlsingle/#using.build-systems.starters
请求响应
请求
postman
简单参数
如果方法形参名称与请求参数名称不匹配,可以使用 @RequestParam 完成映射
原始方法(不要求掌握)
//原始方法
@RestController
public class HelloController {
@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";
}
}
Springboot方式
@RestController
public class HelloController {
// Springboot方式
@RequestMapping("/simpleParam")
public String simpleParam(String name, int age) {
System.out.println(name + ":" + age);
return "OK";
}
}
GET请求
POST请求
请求参数名与方法变量名不同,不能传递
@RequestMapping("/simpleParam")
public String simpleParam(String userName, int age) {
System.out.println(userName + ":" + age);
return "OK";
}
强制传递:注释@RequestParam(name/value="请求参数名", require = true(默认,必须传递name))
@RequestMapping("/simpleParam")
public String simpleParam(@RequestParam(name = "name") String userName, int age) {
System.out.println(userName + ":" + age);
return "OK";
}
不传递会报错,因为默认required=true,除非required=false
required=false,不传递name:
实体参数
要求:请求参数名与形参对象属性名相同
简单实体参数
实体类
public class User {
private String name;
private int age;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
@Override
public String toString() {
return "User{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
}
Springboot方法
@RestController
public class HelloController {
// 实体参数
@RequestMapping("/simplePojo")
public String simplePojo(User user) {
System.out.println(user);
return "OK";
}
}
复杂实体参数
实体类:address实体类不要封装有参构造函数,否则报错
public class Address {
private String province;
private String 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;
}
@Override
public String toString() {
return "Address{" +
"province='" + province + '\'' +
", city='" + city + '\'' +
'}';
}
}
public class User {
private String name;
private int age;
private Address address;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int 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 +
'}';
}
}
Springboot方法
@RestController
public class HelloController {
// 复杂实体方法
@RequestMapping("/complexPojo")
public String complexPojo(User user) {
System.out.println(user);
return "OK";
}
}
数组集合参数
@RestController
public class HelloController {
// 数组集合参数
@RequestMapping("/arrayParam")
public String arrayParam(String[] hobby) {
System.out.println(Arrays.toString(hobby));
return "OK";
}
}
数组参数
集合参数
请求参数名与形参集合名称相同且请求参数为多个,@RequestParam 绑定参数关系
注意:一定要加注解
@RestController
public class HelloController {
// 集合参数
@RequestMapping("/listParam")
public String listParam(@RequestParam List<String> hobby) {
System.out.println(hobby);
return "OK";
}
}
日期时间参数
使用 @DateTimeFormat 注解完成日期参数格式转换
@RestController
public class HelloController {
// 日期时间参数
@RequestMapping("/dateParam")
// 方法形参:加注解指定日期格式,声明一个日期时间对象updateTime
public String dateParam(@DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss") LocalDateTime updateTime) {
System.out.println(updateTime);
return "OK";
}
}
JSON参数
JSON数据键名与形参对象属性名相同,定义POJO类型形参即可接收参数,需要使用 @RequestBody 标识
注意:实体类不要写有参构造器
@RestController
public class HelloController {
@RequestMapping("/jsonParam")
public String jsonParam(@RequestBody User user) {
System.out.println(user);
return "OK";
}
}
// Json参数如下
{
"name": "itheima",
"age": 22,
"address": {
"province": "安徽",
"city": "阜阳"
}
}
路径参数
如果方法形参名称与请求参数名称不匹配,可以使用 @RequestParam 完成映射
@RestController
public class HelloController {
// 路径参数-单个参数
@RequestMapping("/path/{id}")
public String pathParam(@PathVariable Integer id) {
System.out.println(id);
return "OK";
}
}
多个参数
// 多个参数
@RequestMapping("/path/{id}/{name}")
public String pathParam(@PathVariable Integer id, @PathVariable String name) {
System.out.println(id + ":" + name);
return "OK";
}
总结-参数
响应
@RestController
public class RequestController {
// 响应-字符串
@RequestMapping("/Hello")
public String hello() {
System.out.println("Hello!!!");
return "Hello world!!!";
}
// 响应-对象
@RequestMapping("/getAddr")
public Address getAddr() {
Address addr = new Address();
addr.setProvince("广东");
addr.setCity("深圳");
return addr;
}
// 响应-集合
@RequestMapping("/listAddr")
public List<Address> listAddr() {
List<Address> list = new ArrayList<>();
Address addr1 = new Address();
addr1.setProvince("广东");
addr1.setCity("深圳");
Address addr2 = new Address();
addr2.setProvince("陕西");
addr2.setCity("西安");
list.add(addr1);
list.add(addr2);
return list;
}
}
响应数据形式不一,不便管理,难以维护
统一响应结果
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 +
'}';
}
}
@RestController
public class ResponseController {
// 统一响应结果
// 响应-字符串
@RequestMapping("/Hello")
public Result hello() {
System.out.println("Hello!!!");
return Result.success("Hello world!!!");
}
// 响应-对象
@RequestMapping("/getAddr")
public Result getAddr() {
Address addr = new Address();
addr.setProvince("广东");
addr.setCity("深圳");
System.out.println(addr);
return Result.success(addr);
}
// 响应-集合
@RequestMapping("/listAddr")
public Result listAddr() {
List<Address> list = new ArrayList<>();
Address addr1 = new Address();
addr1.setProvince("广东");
addr1.setCity("深圳");
Address addr2 = new Address();
addr2.setProvince("陕西");
addr2.setCity("西安");
list.add(addr1);
list.add(addr2);
System.out.println(addr1);
System.out.println(addr2);
System.out.println(list);
return Result.success(list);
}
}
响应-案例
Springboot项目的静态资源(html,css,js等前端资源)默认存放目录为:classpath:/static 、 classpath:/public、 classpath:/resources
empController
package com.itheima.controller;
import com.itheima.pojo.Emp;
import com.itheima.pojo.Result;
import com.itheima.utils.XmlParserUtils;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import java.util.List;
@RestController
public class empController {
@RequestMapping("/listEmp")
public Result listEmp() {
// 动态获取获取静态文件路径,路径中不含中文
String file = this.getClass().getClassLoader().getResource("emp.xml").getFile();
// 实在不行就拿绝对路径
// String file = "C:\\Users\\bfs\\Desktop\\JavaWeb\\study\\JavaWeb_project\\springboot-web-quickstart\\src\\main\\resources\\emp.xml";
// 加载emp.xml,并解析数据
List<Emp> empList = XmlParserUtils.parse(file, Emp.class);
// 处理gender、job字段
empList.stream().forEach(emp -> {
String gender = emp.getGender(); // gender: 1 男 2 女
if("1".equals(gender)) {
emp.setGender("男");
} else if("2".equals(gender)) {
emp.setGender("女");
}
String job = emp.getJob(); // job: 1:讲师 2:班主任 3:就业指导
if("1".equals(job)) {
emp.setJob("讲师");
} else if("2".equals(job)) {
emp.setJob("班主任");
} else if("3".equals(job)) {
emp.setJob("就业指导");
}
});
// 返回结果
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>
渲染效果
分层解耦
三层结构
文件结构
dao接口
package com.itheima.dao;
import com.itheima.pojo.Emp;
import java.util.List;
public interface EmpDao {
List<Emp> listEmp();
}
dao接口的实现类
package com.itheima.dao.impl;
import com.itheima.dao.EmpDao;
import com.itheima.pojo.Emp;
import com.itheima.utils.XmlParserUtils;
import java.util.List;
public class EmpDaoA implements EmpDao {
@Override
public List<Emp> listEmp() {
// 动态获取获取静态文件路径,路径中不含中文
String file = this.getClass().getClassLoader().getResource("emp.xml").getFile();
// 实在不行就拿绝对路径
// String file = "C:\\Users\\bfs\\Desktop\\JavaWeb\\study\\JavaWeb_project\\springboot-web-quickstart\\src\\main\\resources\\emp.xml";
// 加载emp.xml,并解析数据
List<Emp> empList = XmlParserUtils.parse(file, Emp.class);
return empList;
}
}
service接口
package com.itheima.service;
import com.itheima.pojo.Emp;
import java.util.List;
public interface EmpService {
List<Emp> listEmp();
}
service接口实现类
package com.itheima.service.impl;
import com.itheima.dao.EmpDao;
import com.itheima.dao.impl.EmpDaoA;
import com.itheima.pojo.Emp;
import com.itheima.service.EmpService;
import java.util.List;
public class EmpServiceA implements EmpService {
private EmpDao empDao = new EmpDaoA();
@Override
public List<Emp> listEmp() {
List<Emp> empList = empDao.listEmp();
// 处理gender、job字段
empList.stream().forEach(emp -> {
String gender = emp.getGender(); // gender: 1 男 2 女
if("1".equals(gender)) {
emp.setGender("男");
} else if("2".equals(gender)) {
emp.setGender("女");
}
String job = emp.getJob(); // job: 1:讲师 2:班主任 3:就业指导
if("1".equals(job)) {
emp.setJob("讲师");
} else if("2".equals(job)) {
emp.setJob("班主任");
} else if("3".equals(job)) {
emp.setJob("就业指导");
}
});
return empList;
}
}
controller
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 com.itheima.utils.XmlParserUtils;
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("/listEmpA")
public Result listEmpA() {
List<Emp> list = empService.listEmp();
return Result.success(list);
}
}
存在的问题:耦合
分层解耦
- 内聚:软件中各个功能模块内部的功能联系。
- 耦合:衡量软件中各个层/模块之间的依赖、关联的程度。
- 软件设计原则:高内聚,低耦合
控制反转: Inversion Of Control,简称IOC。对象的创建控制权由程序自身转移到外部(容器),这种思想称为控制反转。
依赖注入: Dependency Injection,简称DI。容器为应用程序提供运行时,所依赖的资源,称之为依赖注入。
Bean对象:IOC容器中创建、管理的对象,称之为bean。
IOC
Bean的声明
要把某个对象交给IOC容器管理,需要在对应的类上加上如下注解之一
声明bean的时候,可以通过value属性指定bean的名字,如果没有指定,默认为类名首字母小写。
使用以上四个注解都可以声明bean,但是在springboot集成web开发中,声明控制器bean只能用@Controller。