Maven

概述

  • 介绍:Maven是apache旗下的一个开源项目,是一款用于管理和构建java项目的工具,标准跨平台(Linux、Windows、MacOS)的自动化项目构建方式。

    • 仓库:用于存储资源,管理各种jar包。
      • 本地仓库:自己计算机上的一个目录。
      • 中央仓库:由Maven团队维护的全球唯一的。 仓库地址:https://repo1.maven.org/maven2/
      • 远程仓库(私服):一般由公司团队搭建的私有仓库。
  • 作用:

    • 依赖管理:方便快捷的管理项目依赖的资源(jar包),避免版本冲突问题
    • 统一项目结构:提供标准、统一的项目结构
    • 项目构建:标准跨平台(Linux、Windows、MacOS)的自动化项目构建方式
  • 官网:http://maven.apache.org/

  • 安装

    1. 解压 apache-maven-3.6.1-bin.zip。

    2. 配置本地仓库:修改 conf/settings.xml 中的为一个指定目录。

      1
      <localRepository>E:\develop\apache-maven-3.6.1\mvn_repo</localRepository>
    3. 配置阿里云私服:修改 conf/settings.xml 中的标签,为其添加如下子标签:

      1
      2
      3
      4
      5
      6
      <mirror>  
      <id>alimaven</id>
      <name>aliyun maven</name>
      <url>http://maven.aliyun.com/nexus/content/groups/public/</url>
      <mirrorOf>central</mirrorOf>
      </mirror>
    4. 配置环境变量: MAVEN_HOME 为maven的解压目录,并将其bin目录加入PATH环境变量。

  • 测试:cmd中输入以下代码查看是否安装成功

    1
    mvn -v

IDE集成Maven

配置Maven环境

  • 选择 IDEA中 File –> Settings –> Build,Execution,Deployment –> Build Tools –> Maven

  • 设置 IDEA 使用本地安装的 Maven,并修改配置文件及本地仓库路径

创建Maven项目

  1. 创建模块,选择Maven,点击Next

  2. 填写模块名称,坐标信息,点击finish,创建完成

  3. 编写 HelloWorld,并运行

  • Maven坐标

    • 什么是坐标?

    • Maven 中的坐标是资源的唯一标识,通过该坐标可以唯一定位资源位置。

    • 使用坐标来定义项目或引入项目中需要的依赖。

    • Maven 坐标主要组成

      • groupId:定义当前Maven项目隶属组织名称(通常是域名反写,例如:com.itheima)

      • artifactId:定义当前Maven项目名称(通常是模块名称,例如 order-service、goods-service)

      • version:定义当前项目版本号

      1
      2
      3
      4
      5
      <dependency>
      <groupId>com.itheima</groupId>
      <artifactId>maven-project01</artifactId>
      <version>1.0-SNAPSHOT</version>
      </dependency>

导入Maven项目

略略略

依赖管理

依赖配置

  • 依赖:指当前项目运行所需要的jar包,一个项目中可以引入多个依赖。

  • 配置:

    1. 在 pom.xml 中编写 <dependencies>标签

    2. <dependencies>标签中 使用<dependency> 引入坐标

    3. 定义坐标的 groupId,artifactId,version

    4. 点击刷新按钮,引入最新加入的坐标

    1
    2
    3
    4
    5
    6
    7
    <dependencies>
    <dependency>
    <groupId>ch.qos.logback</groupId>
    <artifactId>logback-classic</artifactId>
    <version>1.2.3</version>
    </dependency>
    </dependencies>

注意:

  • 如果引入的依赖,在本地仓库不存在,将会连接远程仓库/中央仓库,然后下载依赖。(这个过程会比较耗时,耐心等待)

  • 如果不知道依赖的坐标信息,可以到https://mvnrepository.com/中搜索。

依赖传递

  • 依赖具有传递性

    • 直接依赖:在当前项目中通过依赖配置建立的依赖关系
    • 间接依赖:被依赖的资源如果依赖其他资源,当前项目间接依赖其他资源

  • 排除依赖:排除依赖指主动断开依赖的资源,被排除的资源无需指定版本。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    <dependency>
    <groupId>com.itheima</groupId>
    <artifactId>maven-projectB</artifactId>
    <version>1.0-SNAPSHOT</version>
    <exclusions>
    <exclusion>
    <groupId>junit</groupId>
    <artifactId>junit</artifactId>
    </exclusion>
    </exclusions>
    </dependency>

依赖范围

依赖的jar包,默认情况下,可以在任何地方使用。可以通过 <scope> … </ scope >设置其作用范围。

作用范围:

  • 主程序范围有效。(main文件夹范围内)

  • 测试程序范围有效。(test文件夹范围内)

  • 是否参与打包运行。(package指令范围内)

1
2
3
4
5
6
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.10</version>
<scope>test</scope >
</dependency>
scope主程序测试程序打包(运行)范例
compile(默认)YYYlog4j
test-Y-junit
providedYY-servlet-api
runtime-YYjdbc驱动

生命周期

Maven的生命周期就是为了对所有的maven项目构建过程进行抽象和统一。

Maven中有3套相互独立的生命周期:每套生命周期包含一些阶段(phase),阶段是有顺序的,后面的阶段依赖于前面的阶段。

  • clean:清理工作。

    • pre-clean
    • clean: 移除上一次构建生成的文件
    • post-clean
  • default:核心工作,如:编译、测试、打包、安装、部署等。

    • validate
    • initialize
    • generate-sources
    • process-sources
    • generate-resources
    • process-resources
    • compile: 编译项目源代码
    • process-classes
    • generate-test-sources
    • process-test-sources
    • generate-test-resources
    • process-test-resources
    • test-compile
    • process-test-classes
    • test: 使用合适的单元测试框架运行测试(junit)
    • prepare-package
    • package: 将编译后的文件打包,如:jar、war等
    • verify
    • install: 安装项目到本地仓库
    • deploy
  • site:生成报告、发布站点等。

    • pre-site
    • site
    • post-site
    • site-deploy

注意:在同一套生命周期中,当运行后面的阶段时,前面的阶段都会运行。

执行指定生命周期的两种方式:

  • 在idea中,右侧的maven工具栏,选中对应的生命周期,双击执行。

  • 在命令行中,通过命令执行。

Maven高级

分模块设计与开发

为什么? 将项目按照功能拆分成若干个子模块,方便项目的管理维护、扩展,也方便模块间的相互调用,资源共享。

步骤:

  • 创建maven模块 tlias-pojo,存放实体类。
  • 创建maven模块 tlias-utils,存放相关工具类。

注意事项:分模块开发需要先针对模块功能进行设计,再进行编码。不会先将工程开发完毕,然后进行拆分。

继承与聚合

继承

继承关系

  • 概念:继承描述的是两个工程间的关系,与java中的继承相似,子工程可以继承父工程中的配置信息,常见于依赖关系的继承。
  • 作用:简化依赖配置、统一管理依赖
  • 实现:<parent> … </parent>
  • 步骤:

    1. 创建maven模块 tlias-parent ,该工程为父工程,设置打包方式pom(默认jar)。
    2. 在子工程的pom.xml文件中,配置继承关系。

    注意事项

    • 在子工程中,配置了继承关系之后,坐标中的groupId是可以省略的,因为会自动继承父工程的 。
    • relativePath指定父工程的pom文件的相对位置(如果不指定,将从本地仓库/远程仓库查找该工程)。
    1. 在父工程中配置各个工程共有的依赖(子工程会自动继承父工程的依赖)。

    注意事项:若父子工程都配置了同一个依赖的不同版本,以子工程的为准。

jar:普通模块打包,springboot项目基本都是jar包(内嵌tomcat运行)
war:普通web程序打包,需要部署在外部的tomcat服务器中运行
pom:父工程或聚合工程,该模块不写代码,仅进行依赖管理

版本锁定

  • 在maven中,可以在父工程的pom文件中通过 <dependencyManagement> 来统一管理依赖版本。

注意事项:子工程引入依赖时,无需指定 <version> 版本号,父工程统一管理。变更依赖版本,只需在父工程中统一变更。

  • 自定义属性/引用属性

<dependencyManagement> 与 <dependencies>的区别是什么?

  • <dependencies> 是直接依赖,在父工程配置了依赖,子工程会直接继承下来。
  • <dependencyManagement> 是统一管理依赖版本,不会直接依赖,还需要在子工程中引入所需依赖(无需指定版本)

聚合

  • 聚合:将多个模块组织成一个整体,同时进行项目的构建。

  • 聚合工程:一个不具有业务功能的“空”工程(有且仅有一个pom文件)

  • 作用:快速构建项目(无需根据依赖关系手动构建,直接在聚合工程上构建即

  • maven中可以通过 <modules> 设置当前聚合工程所包含的子模块名称

注意事项:聚合工程中所包含的模块,在构建时,会自动根据模块间的依赖关系设置构建顺序,与聚合工程中模块的配置书写位置无关。

继承与聚合

  • 作用
    • 聚合用于快速构建项目
    • 继承用于简化依赖配置、统一管理依赖
  • 相同点:
    • 聚合与继承的pom.xml文件打包方式均为pom,可以将两种关系制作到同一个pom文件中
    • 聚合与继承均属于设计型模块,并无实际的模块内容
  • 不同点:
    • 聚合是在聚合工程中配置关系,聚合可以感知到参与聚合的模块有哪些
    • 继承是在子模块中配置关系,父模块无法感知哪些子模块继承了自己

私服

  • 私服是一种特殊的远程仓库,它是架设在局域网内的仓库服务,用来代理位于外部的中央仓库,用于解决团队内部的资源共享与资源同步问题。

  • 依赖查找顺序:

    • 本地仓库
    • 私服
    • 中央仓库
  • 资源上传与下载

项目版本:

  • RELEASE(发行版本):功能趋于稳定、当前更新停止,可以用于发行的版本,存储在私服中的RELEASE仓库中。

  • SNAPSHOT(快照版本):功能不稳定、尚处于开发中的版本,即快照版本,存储在私服的SNAPSHOT仓库中。

  1. 设置私服的访问用户名/密码(settings.xml中的servers中配置)
1
2
3
4
5
6
7
8
9
10
11
<server>
<id>maven-releases</id>
<username>admin</username>
<password>admin</password>
</server>
<server>
<id>maven-snapshots</id>
<username>admin</username>
<password>admin</password>
</server>

  1. IDEA的maven工程的pom文件中配置上传(发布)地址
1
2
3
4
5
6
7
8
9
10
<distributionManagement>
<repository>
<id>maven-releases</id>
<url>http://192.168.150.101:8081/repository/maven-releases/</url>
</repository>
<snapshotRepository>
<id>maven-snapshots</id>
<url>http://192.168.150.101:8081/repository/maven-snapshots/</url>
</snapshotRepository>
</distributionManagement>
  1. 设置私服依赖下载的仓库组地址(settings.xml中的mirrors、profiles中配置)
1
2
3
4
5
<mirror>
<id>maven-public</id>
<mirrorOf>*</mirrorOf>
<url>http://192.168.150.101:8081/repository/maven-public/</url>
</mirror>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
<profile>
<id>allow-snapshots</id>
<activation>
<activeByDefault>true</activeByDefault>
</activation>
<repositories>
<repository>
<id>maven-public</id>
<url>http://192.168.150.101:8081/repository/maven-public/</url>
<releases>
<enabled>true</enabled>
</releases>
<snapshots>
<enabled>true</enabled>
</snapshots>
</repository>
</repositories>
</profile>

SpringBoot Web 基础篇

  • 官网:spring.io
  • Spring发展到今天已经形成了一种开发生态圈,Spring提供了若干个子项目,每个项目用于完成特定的功能。

  • Spring Boot 可以帮助我们非常快速的构建应用程序、简化开发、提高效率 。

SpringBootWeb入门

  • 需求:使用 SpringBoot 开发一个web应用,浏览器发起请求 /hello后,给浏览器返回字符串 “Hello World ~”。

  • 步骤

    1. 创建springboot工程,填写模块信息,并勾选web开发相关依赖。

    2. 定义HelloController类,添加方法 hello,并添加注解。

    3. 运行启动类,打开浏览器测试。

HTTP协议

  • 概述

    • 概念:Hyper Text Transfer Protocol,超文本传输协议,规定了浏览器和服务器之间数据传输的规则。
    • 特点:
      1. 基于TCP协议:面向连接,安全
      2. 基于请求-响应模型的:一次请求对应一次响应
      3. HTTP协议是无状态的协议:对于事务处理没有记忆能力。每次请求-响应都是独立的。
        • 缺点:多次请求间不能共享数据。
        • 优点:速度快
  • 请求协议

Host请求的主机名
User-Agent浏览器版本,例如Chrome浏览器的标识类似Mozilla/5.0 … Chrome/79,IE浏览器的标识类似Mozilla/5.0 (Windows NT …) like Gecko
Accept表示浏览器能接收的资源类型,如text/*,image/或者/*表示所有;
Accept-Language表示浏览器偏好的语言,服务器可以据此返回不同语言的网页;
Accept-Encoding表示浏览器可以支持的压缩类型,例如gzip, deflate等。
Content-Type请求主体的数据类型。
Content-Length请求主体的大小(单位:字节)。

注意

  • 请求方式-GET:请求参数在请求行中,没有请求体,如:**/brand/findAll?name=OPPO&status=1**。GET请求大小是有限制的。

  • 请求方式-POST:请求参数在请求体中,POST请求大小是没有限制的。

  • 响应协议

状态码分类说明
1xx响应中-临时状态码,表示请求已经接收,告诉客户端应该继续请求或者如果它已经完成则忽略它。
2xx成功-表示请求已经被成功接收,处理已完成。
3xx重定向-重定向到其他地方;让客户端再发起一次请求以完成整个处理。
4xx客户端错误-处理发生错误,责任在客户端。如: 请求了不存在的资源、客户端未被授权、禁止访问等。
5xx服务器错误-处理发生错误,责任在服务端。如:程序抛出异常等。
响应头说明
Content-Type表示该响应内容的类型,例如text/html,application/json。
Content-Length表示该响应内容的长度(字节数)。
Content-Encoding表示该响应压缩算法,例如gzip。
Cache-Control指示客户端应如何缓存,例如max-age=300表示可以最多缓存300秒。
Set-Cookie告诉浏览器为当前页面所在的域设置cookie。
状态码解释
200客户端请求成功。
404请求资源不存在,般是URL输入有误,或者网站资源被删除了。
500服务器发生不可预期的错误。

状态码大全:https://cloud.tencent.com/developer/chapter/13553

  • 协议解析

Web服务器-Tomcat

  • Web服务器是一个软件程序,对HTTP协议的操作进行封装,使得程序员不必直接对协议进行操作,让Web开发更加便捷。主要功能是 “提供网上信息浏览服务” 。

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/download-90.cgi

  • 安装:绿色版,直接解压即可

  • 卸载:直接删除目录即可

  • 启动:双击:bin\startup.bat

    • 控制台中文乱码:修改conf/ logging.properties

  • 关闭:

    • 直接×掉运行窗口:强制关闭
    • bin\shutdown.bat:正常关闭
    • Ctrl+C:正常关闭

常见问题:

  • 启动窗口一闪而过:检查JAVA_HOME环境变量是否正确配置

  • 端口号冲突:找到对应程序,将其关闭掉

  • 配置Tomcat端口号(conf/server.xml)

注意:HTTP协议默认端口号为80,如果将Tomcat端口号改为80,则将来访问Tomcat时,将不用输入端口号 。

  • Tomcat 部署项目:将项目放置到 webapps 目录下, 即部署完成

入门程序解析

起步依赖:

请求响应

  • 请求(HttpServletRequest):获取请求数据
  • 响应(HttpServletResponse):设置响应数据
  • BS架构:Browser/Server,浏览器/服务器架构模式。客户端只需要浏览器,应用程序的逻辑和数据都存储在服务端。(维护方便 体验一般
  • CS架构:Client/Server,客户端/服务器架构模式。(开发、维护麻烦 体验不错

请求

Postman

Postman是一款功能强大的网页调试与发送网页HTTP请求的Chrome插件。

作用:常用于进行接口测试

简单参数

  • 原始方式:在原始的web程序中,获取请求参数,需要通过HttpServletRequest 对象手动获取。

  • SpringBoot方式:参数名与形参变量名相同,定义形参即可接收参数。如果方法形参名称与请求参数名称不匹配,可以使用 @RequestParam 完成映射。

    注意:@RequestParam中的required属性默认为true,代表该请求参数必须传递,如果不传递将报错。 如果该参数是可选的,可以将required属性设置为false。

    • post传递

实体参数

  • 简单实体对象:请求参数名与形参对象属性名相同,定义POJO接收即可。

  • 复杂实体对象:请求参数名与形参对象属性名相同,按照对象层次结构关系即可接收嵌套POJO属性参数。

数组参数

请求参数名与形参数组名称相同且请求参数为多个,定义数组类型形参即可接收参数

集合参数

请求参数名与形参集合名称相同且请求参数为多个,@RequestParam 绑定参数关系

日期参数

使用 @DateTimeFormat 注解完成日期参数格式转换

JSON参数

JSON数据键名与形参对象属性名相同,定义POJO类型形参即可接收参数,需要使用 @RequestBody 标识

路径参数

通过请求URL直接传递参数,使用{…}来标识该路径参数,需要使用 @PathVariable 获取路径参数

响应

  • 响应数据:字符串、对象、集合

  • ResponseBody

    • 类型:方法注解、类注解
    • 位置:Controller方法上/类上
    • 作用:将方法返回值直接响应,如果返回值类型是 实体对象/集合 ,将会转换为JSON格式响应
    • 说明:@RestController = @Controller + @ResponseBody ;
  • 统一响应结果:Result(code, msg, data)

分层解耦

三层架构

  • controller:控制层,接收前端发送的请求,对请求进行处理,并响应数据。
  • service:业务逻辑层,处理具体的业务逻辑。
  • dao:数据访问层(Data Access Object)(持久层),负责数据访问操作,包括数据的增、删、改、查。

分层解耦

  • 内聚:软件中各个功能模块内部的功能联系。

  • 耦合:衡量软件中各个层/模块之间的依赖、关联的程度。

  • 软件设计原则:高内聚低耦合。

  • 分层思想

    • 控制反转: Inversion Of Control,简称IOC。对象的创建控制权由程序自身转移到外部(容器),这种思想称为控制反转。

    • 依赖注入: Dependency Injection,简称DI。容器为应用程序提供运行时,所依赖的资源,称之为依赖注入。

    • Bean对象:IOC容器中创建、管理的对象,称之为bean

IOC & DI入门

  • 步骤:

    1. Service层 及 Dao层的实现类,交给IOC容器管理。(加上@Component

    2. 为Controller及Service注入运行时,依赖的对象。(加上@Autowired

    3. 运行测试。

IOC详解

  • Bean的声明

    要把某个对象交给IOC容器管理,需要在对应的类上加上如下注解之一:

注解说明位置
@Component声明bean的基础注解不属于以下三类时,用此注解
@Controller@Component的衍生注解标注在控制器类上
@Service@Component的衍生注解标注在业务类上
@Repository@Component的衍生注解标注在数据访问类上(由于与mybatis整合,用的少)

注意

  • 声明bean的时候,可以通过value属性指定bean的名字,如果没有指定,默认为类名首字母小写。
  • 使用以上四个注解都可以声明bean,但是在springboot集成web开发中,声明控制器bean只能用@Controller。
  • Bean组件扫描

    • 前面声明bean的四大注解,要想生效,还需要被组件扫描注解@ComponentScan扫描。

    • @ComponentScan注解虽然没有显式配置,但是实际上已经包含在了启动类声明注解 @SpringBootApplication 中,默认扫描的范围是启动类所在包及其子包。

DI详解

  • Bean注入

    • @Autowired注解,默认是按照类型进行,如果存在多个相同类型的bean,将会报出如下错误:
    • 通过以下几种方案来解决:
      • @Primary
      • @Qualifier
      • @Resource

@Resource 与 @Autowired区别

  • @Autowired 是spring框架提供的注解,而@Resource是JDK提供的注解。

  • @Autowired 默认是按照类型注入,而@Resource默认是按照名称注入

Mybatis

  • MyBatis是一款优秀的持久层框架,用于简化JDBC的开发

  • MyBatis本是 Apache的-个开源项目iBatis,2010年这项目apache迁移到了oole cde,并且改名为MvBatis2013年11月迁移到Github年11月迁移到Github

  • 官网: https://mybatis.org/mybatis-3/zh/index.html

Mybatis入门

快速入门

  • 需求:使用Mybatis查询所有用户数据

  • 步骤:

    1. 准备工作(创建springboot工程、数据库表user、实体类User)
    2. 引入Mybatis的相关依赖,配置Mybatis(数据库连接信息)
    3. 编写SQL语句(注解/XML)
    4. 单元测试

JDBC介绍

数据库连接池

  • 介绍:

    • 数据库连接池是个容器,负责分配、管理数据库连接(Connection)
    • 它允许应用程序重复使用一个现有的数据库连接,而不是再重新建立一个
    • 释放空闲时间超过最大空闲时间的连接,来避免因为没有释放连接而引起的数据库连接遗漏
  • 优势:

    • 资源重用
    • 提升系统响应速度
    • 避免数据库连接遗漏
  • 标准接口:DataSource

    • 官方(sun)提供的数据库连接池接口,由第三方组织实现此接口。
    • 功能:获取连接
  • 常见产品:

  • Druid(德鲁伊)

    • Druid连接池是阿里巴巴开源的数据库连接池项目
    • 功能强大,性能优秀,是 Java 语言最好的数据库连接池之一
  • 切换Druid数据库连接池

    官方地址:https://github.com/alibaba/druid/tree/master/druid-spring-boot-starter

    详见:JDBC学习 | Threewood (threewood1.top) 中的使用优化部分

lombok

  • Lombok是一个实用的Java类库,能通过注解的形式自动生成构造器、getter/setter、equals、hashcode、toString等方法,并可以自动化生成日志变量,简化java开发、提高效率。

  • 依赖

    1
    2
    3
    4
    <dependency>
    <groupId>org.projectlombok</groupId>
    <artifactId>lombok</artifactId>
    </dependency>
注解作用
@Getter/@Setter为所有的属性提供get/set方法
@ToString会给类自动生成易阅读的 toString 方法
@EqualsAndHashCode根据类所拥有的非静态字段自动重写 equals 方法和 hashCode 方法
@Data提供了更综合的生成代码功能(@Getter + @Setter + @ToString + @EqualsAndHashCode)
@NoArgsConstructor为实体类生成无参的构造器方法
@AllArgsConstructor为实体类生成除了static修饰的字段之外带有各参数的构造器方法。

注意:Lombok会在编译时,自动生成对应的 java 代码。我们使用 lombok 时,还需要安装一个 lombok 的插件(idea自带)。

Mybatis基础操作

  • 准备

    • 准备数据库表 emp
    • 创建一个新的springboot工程,选择引入对应的起步依赖(mybatis、mysql驱动、lombok)
    • application.properties中引入数据库连接信息
    • 创建对应的实体类 Emp(实体类属性采用驼峰命名)
    • 准备Mapper接口 EmpMapper
  • 删除

    • 接口方法:

      1
      2
      @Delete("delete from emp where id = #{id}")
      public void delete(Integer id);

    注意:如果mapper接口方法形参只有一个普通类型的参数,#{…} 里面的属性名可以随便写,如:#{id}、#{value}。

    • 日志输出:可以在application.properties中,打开mybatis的日志,并指定输出到控制台。

      1
      2
      // 指定mybatis输出日志的位置,输出控制台
      mybatis.configuration.log-impl=org.apache.ibatis.logging.stdout.StdOutImpl
    • SQL注入:是通过操作输入的数据来修改事先定义好的SQL语句,以达到执行代码对服务器进行攻击的方法。

    • 参数占位符:

      • #{…}: 执行SQL时,会将#{…}替换为?,生成预编译SQL,会自动设置参数值。使用时机:参数传递,都使用#{…}
      • ${…}: 拼接SQL,直接将参数拼接在SQL语句中,存在SQL注入问题。使用时机:如果对表名、列表进行动态设置时使用。
  • 插入

    • 接口方法:

      1
      2
      3
      @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);
    • 描述:在数据添加成功后,需要获取插入数据库数据的主键。如:添加套餐数据时,还需要维护套餐菜品关系表数据。

    • 实现:

      1
      2
      3
      4
      @Options(keyProperty = "id", useGeneratedKeys = true) //会自动将生成的主键值,赋值给emp对象的id属性
      @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);
  • 更新

    • 接口方法:

      1
      2
      @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);
  • 查询(根据ID查询)

    • 接口方法:

      1
      2
      @Select("select * from emp where id = #{id}")
      public Emp getById(Integer id);
  • 数据封装

    • 实体类属性名和数据库表查询返回的字段名一致,mybatis会自动封装。

    • 如果实体类属性名 和 数据库表查询返回的字段名不一致,不能自动封装。

    • 起别名:在SQL语句中,对不一样的列名起别名,别名和实体类属性名一样。

      1
      2
      @Select("select id, username, password, name, gender, image, job, entrydate, dept_id deptId, create_time createTime, update_time updateTime from emp where id = #{id} ")
      public Emp getById(Integer id);
    • 手动结果映射:通过 @Results 及 @Result 进行手动结果映射。

      1
      2
      3
      4
      5
      6
      @Select("select * from emp where id = #{id}")
      @Results({
      @Result(column = "dept_id", property = "deptId"),
      @Result(column = "create_time", property = "createTime"),
      @Result(column = "update_time", property = "updateTime")})
      public Emp getById(Integer id);
    • 开启驼峰命名:如果字段名与属性名符合驼峰命名规则,mybatis会自动通过驼峰命名规则映射。

      1
      2
      // 开启驼峰命名自动映射,即从数据库字段名 a_column 映射到Java 属性名 aColumn。
      mybatis.configuration.map-underscore-to-camel-case=true
  • 查询(条件查询)

    • 接口方法

      1
      2
      @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(String name, Shortgender , LocalDate begin , LocalDate end);

XML映射文件

使用Mybatis的注解,主要是来完成一些简单的增删改查功能。如果需要实现复杂的SQL功能,建议使用XML来配置映射语句。

  • 规范:

    • XML映射文件的名称与Mapper接口名称一致,并且将XML映射文件和Mapper接口放置在相同包下(同包同名)。
    • XML映射文件的namespace属性为Mapper接口全限定名一致。
    • XML映射文件中sql语句的id与Mapper 接口中的方法名一致,并保持返回类型一致。
  • 映射文件:MybatisX 是一款基于 IDEA 的快速开发Mybatis的插件,为效率而生。

  • 官方说明:https://mybatis.net.cn/getting-started.html

Mybatis动态SQL

  • 动态SQL:随着用户的输入或外部条件的变化而变化的SQL语句,我们称为 动态SQL
  • <if>: 用于判断条件是否成立。使用test属性进行条件判断,如果条件为true,则拼接SQL。形式:<if test=”name != null”>…</if>
  • <where>: where 元素只会在子元素有内容的情况下才插入where子句。而且会自动去除子句的开头的AND 或 OR。
  • <set>: 动态地在行首插入 SET 关键字,并会删掉额外的逗号。(用在update语句中)
  • <foreach>: 遍历操作。属性如下:
    • collection:集合名称
    • item:集合遍历出来的元素/项
    • separator:每一次遍历使用的分隔符
    • open:遍历开始前拼接的片段
    • close:遍历结束后拼接的片段
  • <sql>: 定义可重用的 SQL 片段。
  • <include>: 通过属性refid,指定包含的sql片段。

SpringBoot Web开发篇

SpringBootWeb案例

略略略略略。详见https://www.bilibili.com/video/BV1m84y1w7Tb?p=135

SpringBootWeb登录校验

  • 问题分析:在未登录情况下,我们也可以直接访问部门管理、员工管理等功能。

  • 登录校验

    • 登录标记:用户登录成功之后,每一次请求中,都可以获取到该标记。
    • 统一拦截:①过滤器Filter、②拦截器Interceptor

会话技术

  • 会话:用户打开浏览器,访问web服务器的资源,会话建立,直到有一方断开连接,会话结束。在一次会话中可以包含多次请求和响应。
  • 会话跟踪:一种维护浏览器状态的方法,服务器需要识别多次请求是否来自于同一浏览器,以便在同一次会话的多次请求间共享数据
  • 会话跟踪方案:
    • 客户端会话跟踪技术:Cookie
    • 服务端会话跟踪技术:Session
    • 令牌技术

  • 会话跟踪方案对比

JWT令牌

  • 简介:

    全称:JSON Web Token (https://jwt.io/)

    定义了一种简洁的、自包含的格式,用于在通信双方以json数据格式安全的传输信息。由于数字签名的存在,这些信息是可靠的。

    组成:

    • 第一部分:Header(头), 记录令牌类型、签名算法等。 例如:{“alg”:”HS256”,”type”:”JWT”}
    • 第二部分:Payload(有效载荷),携带一些自定义信息、默认信息等。 例如:{“id”:”1”,”username”:”Tom”}
    • 第三部分:Signature(签名),防止Token被篡改、确保安全性。将header、payload,并加入指定秘钥,通过指定签名算法计算而来。

Base64: 是一种基于64个可打印字符(A-Z a-z 0-9 + /)来表示二进制数据的编码方式。

  • 场景:登陆认证

    ① 登录成功后,生成令牌

    ② 后续每个请求,都要携带JWT令牌,系统在每次请求处理之前,先校验令牌,通过后,再处理

  • JWT-生成

    依赖:

    1
    2
    3
    4
    5
    <dependency>
    <groupId>io.jsonwebtoken</groupId>
    <artifactId>jjwt</artifactId>
    <version>0.9.1</version>
    </dependency>

    生成 JWT:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    @Test
    public void genJwt(){
    Map<String,Object> claims = new HashMap<>();
    claims.put(“id”,1);
    claims.put(“username”,“Tom”);
    String jwt = Jwts.builder()
    .setClaims(claims) //自定义内容(载荷)
    .signWith(SignatureAlgorithm.HS256, “atxiong”) //签名算法
    .setExpiration(new Date(System.currentTimeMillis() + 12*3600*1000)) //有效期
    .compact();
    System.out.println(jwt);
    }
  • JWT-校验

    1
    2
    3
    4
    5
    6
    7
    8
    @Test
    public void parseJwt(){
    Claims claims = Jwts.parser()
    .setSigningKey(“atxiong”) //指定签名秘钥
    .parseClaimsJws(“eyJhbGciOiJIUzI1NiJ9.eyJpZCI6MSwiZXhwIjoxNjU5OTk1NTE3LCJ1c2VybmFtZSI6IlRvbSJ9.EUTfeqPkGslekdKBezcWCe7a7xbcIIwB1MXlIccTMwo”) //解析令牌
    .getBody();
    System.out.println(claims);
    }

注意

  • JWT校验时使用的签名秘钥,必须和生成JWT令牌时使用的秘钥是配套的。

  • 如果JWT令牌解析校验时报错,则说明 JWT令牌被篡改 或 失效了,令牌非法

  • 实现

    • 令牌生成:登录成功后,生成JWT令牌,并返回给前端。
      • 引入JWT令牌操作工具类。
      • 登录完成后,调用工具类生成JWT令牌,并返回。

    • 令牌校验:在请求到达服务端后,对令牌进行统一拦截、校验**(Filter、Interceptor)**。

过滤器Filter

概念:Filter 过滤器,是 JavaWeb 三大组件(Servlet、Filter、Listener)之一。

过滤器可以把对资源的请求拦截下来,从而实现一些特殊的功能。

过滤器一般完成一些通用的操作,比如:登录校验、统一编码处理、敏感字符处理等。

  • 快速入门

    1. 定义Filter:定义一个类,实现 Filter 接口,并重写其所有方法。

    1. 配置Filter:Filter类上加 @WebFilter 注解,配置拦截资源的路径。引导类上加 @ServletComponentScan 开启Servlet组件支持

  • 详解

    • 执行流程

    • 拦截路径:Filter 可以根据需求,配置不同的拦截资源路径
    拦截路径urlPatterns值含义
    拦截具体路径/login只有访问 /login 路径时,才会被拦截
    目录拦截/emps/*访问/emps下的所有资源,都会被拦截
    拦截所有/*访问所有资源,都会被拦截
    • 过滤器链:
      • 介绍:一个web应用中,可以配置多个过滤器,这多个过滤器就形成了一个过滤器链
      • 顺序:注解配置的Filter,优先级是按照过滤器类名(字符串)的自然排序。
  • 登录校验Filter-流程

    • 获取请求url。
    • 判断请求url中是否包含login,如果包含,说明是登录操作,放行。
    • 获取请求头中的令牌(token)。
    • 判断令牌是否存在,如果不存在,返回错误结果(未登录)。
    • 解析token,如果解析失败,返回错误结果(未登录)。
    • 放行。

拦截器Interceptor

  • 概念:是一种动态拦截方法调用的机制,类似于过滤器。Spring框架中提供的,用来动态拦截控制器方法的执行。
  • 作用:拦截请求,在指定的方法调用前后,根据业务需要执行预先设定的代码。

  • 快速入门

    1. 定义拦截器,实现HandlerInterceptor接口,并重写其所有方法。
    1. 注册拦截器
  • 详解

    • 拦截路径
    拦截路径含义举例
    /*一级路径能匹配/depts,/emps,/login,不能匹配 /depts/1
    /**任意级路径能匹配/depts,/depts/1,/depts/1/2
    /depts/*/depts下的一级路径能匹配/depts/1,不能匹配/depts/1/2,/depts
    /depts/**/depts下的任意级路径能匹配/depts,/depts/1,/depts/1/2,不能匹配/emps/1
    • 执行流程

Filter 与 Interceptor的区别

  • 接口规范不同:过滤器需要实现Filter接口,而拦截器需要实现HandlerInterceptor接口。
  • 拦截范围不同:过滤器Filter会拦截所有的资源,而Interceptor只会拦截Spring环境中的资源。
  • 登录校验Interceptor-流程

    • 获取请求url。
    • 判断请求url中是否包含login,如果包含,说明是登录操作,放行。
    • 获取请求头中的令牌(token)。
    • 判断令牌是否存在,如果不存在,返回错误结果(未登录)。
    • 解析token,如果解析失败,返回错误结果(未登录)。
    • 放行。

异常处理

程序开发过程中不可避免的会遇到异常现象。出现异常,该如何处理?

  • 方案一:在Controller的方法中进行try…catch处理 代码臃肿、不推荐
  • 方案二:全局异常处理器 简单、优雅、推荐

全局异常处理器

1
2
3
4
5
6
7
8
@RestControllerAdvice
public class GlobalExceptionHandler {
@ExceptionHandler(Exception.class)
public Result ex(Exception ex){
ex.printStackTrace();
return Result.error(" 对不起,操作失败,请联系管理员 ");
}
}

@RestControllerAdvice = @ControllerAdvice + @ResponseBody

Spring事务管理

事务回顾

概念:事务 是一组操作的集合,它是一个不可分割的工作单位,这些操作 要么同时成功,要么同时失败。

操作:

  • 开启事务(一组操作开始前,开启事务):start transaction / begin ;
  • 提交事务(这组操作全部成功后,提交事务):commit;
  • 回滚事务(中间任何一个操作出现异常,回滚事务):rollback ;

spring事务管理

注解:@Transactional

位置:业务(service)层的方法上、类上、接口上

作用:将当前方法交给spring进行事务管理,方法执行前,开启事务;成功执行完毕,提交事务;出现异常,回滚事务

1
2
3
4
5
#开启事务管理日志
logging:
level:
org.springframework.jdbc.support.JdbcTransactionManager: debug

事务属性-回滚

rollbackFor

默认情况下,只有出现 RuntimeException 才回滚异常。rollbackFor属性用于控制出现何种异常类型,回滚事务。

事务属性-传播行为

propagation

事务传播行为:指的就是当一个事务方法被另一个事务方法调用时,这个事务方法应该如何进行事务控制。

属性值含义
REQUIRED【默认值】需要事务,有则加入,无则创建新事务
REQUIRES_NEW需要新事务,无论有无,总是创建新事务
SUPPORTS支持事务,有则加入,无则在无事务状态中运行
NOT_SUPPORTED不支持事务,在无事务状态下运行,如果当前存在已有事务,则挂起当前事务
MANDATORY必须有事务,否则抛异常
NEVER必须没事务,否则抛异常
  • 场景
    • REQUIRED :大部分情况下都是用该传播行为即可。
    • REQUIRES_NEW :当我们不希望事务之间相互影响时,可以使用该传播行为。比如:下订单前需要记录日志,不论订单保存成功与否,都需要保证日志记录能够记录成功。

AOP

AOP基础

AOP概述

  • AOP:Aspect Oriented Programming(面向切面编程、面向方面编程),其实就是面向特定方法编程。
  • 场景:案例部分功能运行较慢,定位执行耗时较长的业务方法,此时需要统计每一个业务方法的执行耗时。

  • 优势

  • 实现:动态代理是面向切面编程最主流的实现。而SpringAOP是Spring框架的高级技术,旨在管理bean对象的过程中,主要通过底层的动态代理机制,对特定的方法进行编程。

AOP快速入门

  • 导入依赖:在pom.xml中导入AOP的依赖

    1
    2
    3
    4
    <dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-aop</artifactId>
    </dependency>
  • 编写AOP程序:针对于特定方法根据业务需要进行编程

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    @Component
    @Aspect
    public class TimeAspect {
    @Around("execution(* com.atxiong.service.*.*(..))")
    public Object recordTime(ProceedingJoinPoint proceedingJoinPoint) throws Throwable {
    long begin = System.currentTimeMillis();
    Object object = proceedingJoinPoint.proceed(); //调用原始方法运行
    long end = System.currentTimeMillis();
    log.info(proceedingJoinPoint.getSignature()+"执行耗时: {}ms", end - begin);
    return object;
    }
    }

AOP核心概念

  • 连接点:JoinPoint,可以被AOP控制的方法(暗含方法执行时的相关信息)
  • 通知:Advice,指哪些重复的逻辑,也就是共性功能(最终体现为一个方法)
  • 切入点:PointCut,匹配连接点的条件,通知仅会在切入点方法执行时被应用
  • 切面:Aspect,描述通知与切入点的对应关系(通知+切入点)
  • 目标对象:Target,通知所应用的对象

  • AOP执行流程

AOP进阶

通知类型

  • @Around:环绕通知,此注解标注的通知方法在目标方法前、后都被执行
  • @Before:前置通知,此注解标注的通知方法在目标方法前被执行
  • @After :后置通知,此注解标注的通知方法在目标方法后被执行,无论是否有异常都会执行
  • @AfterReturning : 返回后通知,此注解标注的通知方法在目标方法后被执行,有异常不会执行
  • @AfterThrowing : 异常后通知,此注解标注的通知方法发生异常后执行

注意事项:

  • @Around环绕通知需要自己调用 ProceedingJoinPoint.proceed() 来让原始方法执行,其他通知不需要考虑目标方法执行
  • @Around环绕通知方法的返回值,必须指定为Object,来接收原始方法的返回值。
  • PointCut:该注解的作用是将公共的切点表达式抽取出来,需要用到时引用该切点表达式即可。

通知顺序

当有多个切面的切入点都匹配到了目标方法,目标方法运行时,多个通知方法都会被执行。

执行顺序:

  1. 不同切面类中,默认按照切面类的类名字母排序
    • 目标方法前的通知方法:字母排名靠前的先执行
    • 目标方法后的通知方法:字母排名靠前的后执行
  2. @Order(数字) 加在切面类上来控制顺序
    • 目标方法前的通知方法:数字小的先执行
    • 目标方法后的通知方法:数字小的后执行

切入点表达式

  • 切入点表达式:描述切入点方法的一种表达式

  • 作用:主要用来决定项目中的哪些方法需要加入通知

  • 常见形式:

    1. execution(……):主要根据方法的返回值、包名、类名、方法名、方法参数等信息来匹配,语法为:
    1
    execution(访问修饰符?  返回值  包名.类名.?方法名(方法参数) throws 异常?)
    • 其中带 ? 的表示可以省略的部分

      • 访问修饰符:可省略(比如: public、protected)
      • 包名.类名: 可省略
      • throws 异常:可省略(注意是方法上声明抛出的异常,不是实际抛出的异常)
    • 可以使用通配符描述切入点

      • * :单个独立的任意符号,可以通配任意返回值、包名、类名、方法名、任意类型的一个参数,也可以通配包、类、方法名的一部分
      1
      execution(* com.*.service.*.update*(*))
      • .. :多个连续的任意符号,可以通配任意层级的包,或任意类型、任意个数的参数
      1
      execution(* com.itheima..DeptService.*(..))

    注意事项:根据业务需要,可以使用 且(&&)、或(||)、非(!) 来组合比较复杂的切入点表达式。

    • 书写建议
      • 所有业务方法名在命名时尽量规范,方便切入点表达式快速匹配。如:查询类方法都是 find 开头,更新类方法都是 update开头。
      • 描述切入点方法通常基于接口描述,而不是直接描述实现类,增强拓展性。
      • 在满足业务需要的前提下,尽量缩小切入点的匹配范围。如:包名匹配尽量不使用 ..,使用 * 匹配单个包。
    1. @annotation(……) :用于匹配标识有特定注解的方法。
    1
    @annotation(com.itheima.anno.Log)

连接点

  • 在Spring中用 JoinPoint 抽象了连接点,用它可以获得方法执行时的相关信息,如目标类名、方法名、方法参数等。
    • 对于 @Around 通知,获取连接点信息只能使用 ProceedingJoinPoint
    • 对于其他四种通知,获取连接点信息只能使用 JoinPoint ,它是 ProceedingJoinPoint 的父类型

AOP案例

略略略略略。详见https://www.bilibili.com/video/BV1m84y1w7Tb?p=182

SpringBoot Web进阶篇

配置优先级

  • SpringBoot 中支持三种格式的配置文件的优先级为:application.properties > application.yml > application.yaml

注意:虽然springboot支持多种格式配置文件,但是在项目开发时,推荐统一使用一种格式的配置 (yml是主流)。

  • SpringBoot 除了支持配置文件属性配置,还支持 Java系统属性  命令行参数 的方式进行属性配置。

①. 执行maven打包指令package

②. 执行java指令,运行jar包

1
java -Dserver.port=9000 -jar tlias-web-management-0.0.1-SNAPSHOT.jar --server.port=10010

注意:Springboot项目进行打包时,需要引入插件 spring-boot-maven-plugin (基于官网骨架创建项目,会自动添加该插件)

  • 优先级(低 —> 高)
    • application.yaml(忽略)
    • application.yml
    • application.properties
    • java系统属性(-Dxxx=xxx)
    • 命令行参数(–xxx=xxx)

Bean管理

获取bean

  • 默认情况下,Spring项目启动时,会把bean都创建好放在IOC容器中,如果想要主动获取这些bean,可以通过如下方式:

    • 根据name获取bean:
    1
    Object getBean(String name)
    • 根据类型获取bean:
    1
    <T> T getBean(Class<T> requiredType)
    • 根据name获取bean(带类型转换):
    1
    <T> T getBean(String name, Class<T> requiredType)

注意事项:上述所说的 【Spring项目启动时,会把其中的bean都创建好】还会受到作用域及延迟初始化影响,这里主要针对于 默认的单例非延迟加载的bean而言。

bean作用域

  • Spring支持五种作用域,后三种在web环境才生效:
作用域说明
singleton容器内同 名称 的 bean 只有一个实例(单例)(默认)
prototype每次使用该 bean 时会创建新的实例(非单例)
request每个请求范围内会创建新的实例(web环境中,了解)
session每个会话范围内会创建新的实例(web环境中,了解)
application每个应用范围内会创建新的实例(web环境中,了解)
  • 可以通过 @Scope 注解来进行配置作用域:
1
2
3
4
5
@Scope("prototype")
@RestController
@RequestMapping("/depts")
public class DeptController {
}

注意事项:

  • 默认singleton的bean,在容器启动时被创建,可以使用@Lazy注解来延迟初始化(延迟到第一次使用时)。
  • prototype的bean,每一次使用该bean的时候都会创建一个新的实例。
  • 实际开发当中,绝大部分的Bean是单例的,也就是说绝大部分Bean不需要配置scope属性。

第三方bean

  • @Bean:如果要管理的 bean 对象来自于第三方(不是自定义的),是无法用 @Component 及衍生注解声明 bean 的,就需要用到 @Bean注解。
  • 若要管理的第三方bean对象,建议对这些bean进行集中分类配置,可以通过 @Configuration 注解声明一个配置类。

注意事项:

  • 通过@Bean注解的name或value属性可以声明bean的名称,如果不指定,默认bean的名称就是方法名。
  • 如果第三方bean需要依赖其它bean对象,直接在bean定义方法中设置形参即可,容器会根据类型自动装配。
  • @Component 及衍生注解 与 @Bean注解使用场景?
    • 项目中自定义的,使用@Component及其衍生注解
    • 项目中引入第三方的,使用@Bean注解

SpringBoot原理

起步依赖

Spring Boot Reference Documentation

自动配置

SpringBoot的自动配置就是当spring容器启动后,一些配置类、bean对象就自动存入到了IOC容器中,不需要我们手动去声明,从而简化了开发,省去了繁琐的配置操作。

  • 自动配置原理

    • 方案一(不推荐):@ComponentScan 组件扫描
    1
    2
    3
    4
    @ComponentScan({"com.example","com.itheima,com.alibaba","com.google","org.springframework","org.mybatis",...})
    @SpringBootApplication
    public class SpringbootWebConfig2Application {
    }
    • 方案二:@Import 导入。使用@Import导入的类会被 Spring 加载到 IOC 容器中,导入形式主要有以下几种:
      • 导入 普通类
      • 导入 配置类
      • 导入 ImportSelector 接口实现类
      • @EnableXxxx注解,封装@Import注解 (SpringBoot 使用的)
  • 源码跟踪

@SpringBootApplication

该注解标识在SpringBoot工程引导类上,是SpringBoot中最最最重要的注解。该注解由三个部分组成:

  • @SpringBootConfiguration:该注解与 @Configuration 注解作用相同,用来声明当前也是一个配置类。
  • @ComponentScan:组件扫描,默认扫描当前引导类所在包及其子包。
  • @EnableAutoConfiguration:SpringBoot实现自动化配置的核心注解

SpringBoot 会根据 @Conditional 注解条件装配!

  • Conditional

    • 作用:按照一定的条件进行判断,在满足给定条件后才会注册对应的 bean 对象到 Spring IOC 容器中。
    • 位置:方法、类
      • @Conditional 本身是一个父注解,派生出大量的子注解:
      • @ConditionalOnClass:判断环境中是否有对应字节码文件,才注册bean到IOC容器。
      • @ConditionalOnMissingBean:判断环境中没有对应的 bean(类型 或 名称) ,才注册bean到IOC
      • @ConditionalOnProperty:判断配置文件中有对应属性和值,才注册bean到IOC容器。
  • 自动配置-案例

略略略略略。详见https://www.bilibili.com/video/BV1m84y1w7Tb?p=192