后端部分
Maven
Maven(apache旗下)是一款用于管理和构建java项目的工具,它基于项目对象模型POM(Project Object Model)的概念,通过一小段描述信息来管理项目的构建。
apache: 开源软件基金会
Maven的作用
- 依赖管理
方便快捷的管理项目依赖的资源(jar包),避免版本冲突问题
- 项目构建
标准跨平台(Linux, Windows、MacOS)的自动化项目构建方式 (清理、编译、测试、打包、发布)
- 统一项目结构
提供标准、统一的项目结构
仓库
仓库: 用于存储资源,管理各种jar包
- 本地仓库: 自己计算机上的一个目录
- 中央仓库: 由Maven团队维护的全球唯一的。仓库地址: https://repo1.maven.org/maven2/
- 远程仓库(私服): 一般由公司团队搭建的私有仓库
Maven坐标
- 什么是坐标
Maven中的坐标是资源的唯一标识,通过该坐标可以唯一定位资源位置。
使用坐标来定义项目或引入项目中需要的依赖。
- Maven坐标主要组成
groupId:定义当前Mave项目隶属组织名称(通常是域名反写, 例如: com.xtzy)
artifactId: 定义当前Maven项目名称(通过是模块名称,例如order-service)
version: 定义当前版本号
HTTP协议
概念
Hyper Text Transfer Protocol 超文本传输协议,规定了浏览器和服务器之间数据传输的规则。
特点
- 基于TCP协议: 面向连接,安全
- 基于请求-响应模型的: 一次请求对应一次响应
- HTTP协议是无状态的协议: 对于事务处理没有记忆能力.每次请求-响应都是独立的。
- 缺点: 多次亲贵之间不能共享数据。
- 优点: 速度快
多次请求没有状态,对于事务处理没有记忆能力,每次请求-响应都是单独的
HTTP-请求数据格式
HTTP-响应数据格式
常见的响应状态码
HTTP 响应状态码 - HTTP | MDN (mozilla.org)
HTTP-协议解析
Tomcat
Web服务器:
- 对HTTP协议操作进行封装,简化web程序开发
- 部署web项目,对外提供网上信息浏览服务。
请求响应
postman
Postman是一款功能强大的网页调试与发送网页HTTP请求的Chrome插件。
作用:常用于进行接口测试
简单参数
- 原始方式(繁琐 不推荐)
在原始的web程序中,获取请求参数,需要通过HttpServletRequest对象手动获取
- SpringBoot方式
简单参数: 参数名与形参变量名相同,定义形参即可接收参数。
@RequestMapping("/simpleParam")
public String simpleParam(String name, Integer age){
System.out.println(name+":" + age);
return "0K";
}
简单参数: 如果方法形参名称与请求参数名称不匹配,可以使用@RequestParam完成映射。
@RequestMapping("/simpleParam")
public String simpleParam(@RequestParam(name ="name") String username, Integer age){
System.out.println(username+":" + age);
return "0K";
}
注意事项:
- @RequestParam中的required属性默认为true,代表该请求参数必须传递,如果不传递将报错。如果该参数是可选的,可以将required属性设置为false。
报错400是浏览器的错误。
实体参数
- 简单实体对象: 请求参数名与形参对象属性名相同.定义POJO接收即可
- 复杂实体对象: 请求参数名与形参对象属性名相同,按照对象层次结构关系即可接收嵌套POJO属性参数.
数组集合参数
- 数组参数: 请求参数名与形参数组名称相同且请求参数为多个,定义数组类型形参即可接收参数
@RequestMapping("/arrayParam")
public String arrayParam(String[] hobby) {
System.out.println(Array.toString(hobby));
return "OK";
}
-
集合参数: 请求参数名与形参集合名称相同且请求参数为多个,@RequestParam绑定参数关系
@RequestMapping("/listParam") public String listParam(@RequestParam List
hobby) { System.out.println(hobby); return "OK"; }
日期参数
- 日期参数: 使用@DateTimeFormat注解完成日期参数格式转换
@RequestMapping("/dateParam")
public String dateParam(@DateTimeFormat(pattern = "yyyy-MM-dd HH:MM:mm:ss") LocalDateTime updateTime){
System.out.println(updateTime);
return "OK";
}
JSON参数
- JSON参数: JSON数据键名与形参对象属性名相同,定义POJO类型形参即可接收参数,需要使用@RequestBody标识。
@RequestMapping("/jsonParam")
public String jsonParam(@RequestBody User user){
System.out.println(user);
return "OK";
}
路径参数
- 路径参数; 通过请求URL直接传递参数,使用{...}来标识该路径参数,需要使用@PathVariable获取路径参数
@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";
}
响应数据
@ResponseBody
- 类型; 方法注解、类注解
- 位置: Controller方法上/类上
- 作用: 将方法返回值直接响应,如果返回值类型是实体对象/集合,将会转换为JSON格式响应
- 说明: @RestController = @Controller + @ResponseBody;
统一管理
Result类
package com.xtzy.pojo;
// 统一响应结果封装类
public class Result {
private Integer code; // 1 成功 ,0 失败
private String msg; // 提示信息
private Object 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) {
}
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 +
'}';
}
}
小案例
案例: 获取员工数据,返回统一响应结果,在页面渲染展示
- 加载并解析emp.xml文件中的数据,完成数据处理,并在页面进行展示。
// emp.xml
<emps>
<emp>
<name>金毛狮王</name>
<age>55</age
<image>https://cdn.jsdelivr.net/gh/xtzyyyyy/blogImage@main/img/qiu.jpg</image>
<gender>1</gender>
<!-- 1 讲师 2 班主任 3 就业指导 -->
<job>1</job>
</emp>
<emp>
<name>白眉鹰王</name>
<age>65</age <image>https://cdn.jsdelivr.net/gh/xtzyyyyy/blogImage@main/img/gd1.jpg</image>
<gender>1</gender>
<!-- 1 讲师 2 班主任 3 就业指导 -->
<job>1</job>
</emp>
</emps>
分层解耦
三层架构
拆分前后对比
分层解耦(IOC-DI引入)
- 内聚: 软件中各个功能模块内部的功能联系
- 耦合: 衡量软件中各个层/模块之间的依赖、关联的程度。
@Compont
将当前类交给IOC容器管理,成为IOC容器中的bean
@Autowired
运行时,IOC容器会提供该类型的bean对象,并赋值给该变量- 依赖注入,即默认按照类型自动装配
IOC&DI-IOC详解
Bean的声明(衍生注解)
@RestController
@RestController = @Controller + @ResponseBody
Bean组件扫描
- 前面声明bean的四大注解,要想生效,还需要被组件扫描注解@ComponentScan扫描。
- @ComponentScan注解虽然没有显式配置,但是实际上已经包含在了启动类声明注解@SpringBootApplication中,默认扫描的范围是启动类所在包及其子包。
默认扫描当前包及其子包
IOC&DI-DI详解
Bean注入
@Resource与Autowired区别
- @Autowired是spring框架提供的注解,而@Resource是JDK提供的注解
- @Autowired默认是按照类型注入的.而@Resource默认是按照名称注入的
Mysql
什么是数据库?
- 数据库: DataBase(DB),是存储和管理数据的仓库。
- 数据库管理系统: DataBase Management System(DBMS),操纵和管理数据库的大型软件。
- SQL: Structured Query Language,操作关系型数据库的编程语言,定义了一套操作关系型数据库统一标准。
where之后不能使用聚合函数,having可以
起始索引=(页码-1) * 展示记录数
Mybatis
- MyBatis是一款优秀的持久层框架,用于简化JDBC的开发
- MyBatis本是Apache的一个开源项目IBatis,2010年这个项目由apache迁移到了google code,并且改名为Mybatis。2013年11月迁移到Github.
- 官网:https://mybatis.org/mybatis-3/
使用Mybatis查询所有用户数据
步骤:
- 准备工作(插件springboot工程、数据库表user、实体类User)
- 引入Mybatis的相关依赖,配置Mybatis(数据库的连接信息)
- 编写SQL语句(注解/XML)
@Mapper
在运行时,会自动生成该接口的实现类对象(代理对象),并且将该对象交给IOC容器管理
配置SQL提示
JDBC
Java DataBase Connectivity: 使用Java语言操作关系型数据库的一套API。
数据库连接池
- 是一个容器,负责分配、管理数据库连接(Connection)
- 优势: 优势复用、提升系统响应速度
- 接口: DataSource
- 产品: C3P0、DBCP、Druid、Hikari
lombok
- Lombok是一个实用的java类库,能通过注解的形式自动生成构造器、getter/setter、equals、hashcode、toString等方法,并可以自动化生成日志变量,简化java开发,提高效率。
注意事项:
- Lombok会在编译时,自动生成对应的java代码。我们使用lombok时,还需要安装一个lombok的插件(idea自带)
Test
package com.xtzy;
import com.xtzy.mapper.EmpMapper;
import com.xtzy.pojo.Emp;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import java.time.LocalDate;
import java.time.LocalDateTime;
@SpringBootTest
class SpringbootMybatisCrudApplicationTests {
@Autowired
private EmpMapper empMapper;
@Test
public void testDelete() {
int delete = empMapper.delete(17);
System.out.println(delete);
}
@Test
public void testInsert() {
Emp emp = new Emp();
emp.setUsername("Tom");
emp.setName("汤姆");
emp.setImage("1.jpg");
emp.setGender((short)1);
emp.setJob((short)1);
emp.setEntrydate(LocalDate.of(2000, 1, 1));
emp.setCreateTime(LocalDateTime.now());
emp.setUpdateTime(LocalDateTime.now());
emp.setDeptId(1);
empMapper.insert(emp);
}
@Test
public void testUpdate() {
Emp emp = new Emp();
emp.setId(18);
emp.setUsername("Tom1");
emp.setName("汤姆1");
emp.setImage("1.jpg");
emp.setGender((short)1);
emp.setJob((short)1);
emp.setEntrydate(LocalDate.of(2000, 1, 1));
emp.setCreateTime(LocalDateTime.now());
emp.setUpdateTime(LocalDateTime.now());
emp.setDeptId(1);
empMapper.update(emp);
}
@Test
public void testGetById() {
Emp emp = empMapper.getById(1);
System.out.println(emp);
}
}
Mybatis基础操作-删除
接口方法写在mapper文件夹下的类中。
- SQL语句:
delete from emo where id = 17;
- 接口方法:
@Delete("delete from emp where id = #{id}")
public int delete(Integer id);
Mybatis基础操作-删除
日志输出
- 可以在application.properties中,打开mybatis的日志,并指定输入到控制台。
# 指定mybatis输出日志的位置,输出到控制台
mybatis.configuration.log-impl=org.apache.ibatis.logging.stdout.StdOutImpl
预编译SQL
优势:
- 性能更高
- 更安全(防止SQL注入)
SQL注入
- SQL注入是通过操作输入的数据来修改事先定义好的sql语句,以达到执行代码对服务器进行攻击的方法。
' or '1' = '1
参数占位符(面试题)
Mybatis基础操作-新增
- SQL语句:
insert into emp(username, name, gender, image, job, entrydate, dept_id, create_time, update_time)
values ('Tom','汤姆','1','1.jpg',1, '2005-01-01', 1, now(), now());
- 接口方法
@Insert("insert into emp(username, name, gender, image, job, entrydate, dept_id, create_time, update_time)" +
" values (#{username}, #{name}, #{gender}, #{image},#{job},#{entrydate},#{deptId},#{createTime},#{updateTime})")
public void insert(Emp emp);
属性名要写成驼峰命名
Mybatis基础操作-新增(主键返回)
- 描述: 在数据添加成功后,需要获取插入数据库数据的主键。如: 添加套餐数据时,还需要维护套餐菜品关系表数据。
- 实现
@Options(keyProperty="id",useGeneatedKeys=true)
@Insert(”...“)
Mybatis基础操作-更新
- SQL语句:
update emp set username = '', name = '', gender = '', image = '',
job = '', entrydate = '', dept_id = '', update_time = '' where id = 1;insert into emp(username, name, gender, image, job, entrydate, dept_id, create_time, update_time)
values ('Tom','汤姆','1','1.jpg',1, '2005-01-01', 1, now(), now());
- 接口方法
@Update("update emp set username = #{username}, name = #{name}, gender = #{gender}, image = #{image}," +
"job = #{job}, entrydate = #{entrydate}, dept_id = #{deptId}, update_time = #{updateTime} where id = #{id};")
public void update(Emp emp);
属性名要写成驼峰命名
Mybatis基础操作-查询(根据id查询)
- SQL语句:
select * from emp where id = 1;
- 接口方法
@Select("select * from emp where id = #{id}")
public Emp getById(Integer id);
数据封装
Emp(id=1, username=jinyong, password=123456, name=金庸, gender=1, image=1.jpg, job=4, entrydate=2000-01-01, deptId=null, createTime=null, updateTime=null)
- 实体类属性名和数据库表查询返回的字段名一致,mybatis会自动封装。
- 如果实体类属性名和 数据库表查询返回的字段名不一致,不能自动封装。
不一致的字段导致结果为null的解决方法
// 方案一: 给字段取别名, 让别名与实体类属性一致
// 方案二: 通过@ResultMap注解, 为查询结果指定映射关系
// 方案三: 开启mybatis的驼峰命名自动映射开关 --- a_column ----> aColumn
mybatis.configuration.map-underscore-to-camel-case=true (写在application.properties中)
Mybatis基础操作-查询(条件查询)
- SQL语句:
select * from emp where name like '%张%' and gender = 1 and entrydate between '2010-01-01' and '2020-01-01' order by update_time desc
-- 改进(推荐)
select * from emp where name like concat('%', '张', '%') and gender = 1 and entrydate between '2010-01-01' and '2020-01-01' order by update_time desc
- 接口方法
@Select("select * from emp where name like '%${name}%' and gender = #{gender} and " +
"entrydate between #{begin} and #{end} order by update_time desc")
public List<Emp> list(@Param("name") String name,@Param("gender") Short gender,@Param("begin") LocalDate begin, @Param("end") LocalDate end);
-- 改进
@Select("select * from emp where name like concat('%', #{name}, '%') and gender = #{gender} and " +
"entrydate between #{begin} and #{end} order by update_time desc")
public List<Emp> list(@Param("name") String name,@Param("gender") Short gender,@Param("begin") LocalDate begin, @Param("end") LocalDate end);
参数名说明
XML映射文件
规范
- XML映射文件的名称与Mapper接口名称一致,并且将XML映射文件和Mapper接口放置在相同包下(同包同名)
- XML映射文件的namespace属性为Mapper接口全限定名一致。
- XML映射文件中SQL语句的id与Mapper接口中的方法名一致,并保持返回类型一致。
tips: 在resources文件夹下创建多级目录要使用/
resultType: 单条记录所封装的类型
MybatisX
- Mybatisx是一款基于IDEA的快速开发Mybatis的插件,为效率而生。
Mybatis动态SQL
随着用户的输入或外部条件的变化而变化的SQL语句,我们称为动态SQL。
< if >
用户判断条件是否成立,使用test属性进行条件判断,如果条件为true,则拼接sql。
< where >
where元素只会在子元素有内容的情况下才插入where子句。而且会自动去除子句的开头的AND或OR
< set>
用来替换set关键字,去除字段之后多余的逗号。
< foreach>
用于批量操作当中。
sql%include
- < sql >: 定义可重用的SQL片段。
- < include>: 通过属性refid,指定包含的sql片段
xml文件
<!-- xml 文件模板-->
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.xtzy.mapper.EmpMapper">
<sql id="commonSelect"> select id, username, password, name, gender, image, job, entrydate, dept_id, create_time, update_time from emp </sql>
<select id="list" resultType="com.xtzy.pojo.Emp">
<!-- select *
from emp -->
<include refid="commonSelect"/>
<where>
<if test="name != null">
name like concat('%', #{name}, '%')
</if>
<if test="gender != null">
and gender = #{gender}
</if>
<if test="begin != null and end != null">
and entrydate between #{begin} and #{end}
</if>
</where>
order by update_time desc
</select>
<!-- 动态更新员工 -->
<update id="update2">
update emp
<set>
<if test="username != null">username = #{username},</if>
<if test="name != null">name = #{name},</if>
<if test="gender != null">gender = #{gender},</if>
<if test="image != null">image = #{image},</if>
<if test="job != null">job = #{job},</if>
<if test="entrydate != null">entrydate = #{entrydate},</if>
<if test="deptId != null">dept_id = #{deptId},</if>
<if test="updateTime != null">update_time = #{updateTime}</if>
</set>
where id = #{id}
</update>
<!-- 批量删除员工 (18,19,20) -->
<!--
collection: 遍历的集合
item: 遍历出来的元素
separator: 分隔符
open: 遍历开始前拼接的SQL片段
close: 遍历结束后拼接的SQL片段
-->
<delete id="deleteByIds">
delete from emp where id in
<foreach collection="ids" item="id" separator="," open="(" close=")"> #{id} </foreach>
</delete>
</mapper>