分模块设计与开发

如果都是一个整体,不便维护,难以复用

image-20240311165526006

image-20240311170348905

分模块设计

image-20240311171016127

直接在tlias-web-management里引入tlias-pojo和tlias-utils的依赖

1
2
3
创建maven模块 tlias-pojo,存放实体类。

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

image-20240311171024408

step1:创建maven模块tlias-pojo,存放实体类

image-20240311171425231 image-20240311171559834 image-20240311171641900

step2:在主程序中引用模块

image-20240311172832257

继承与聚合

继承

概念:继承描述的是两个工程之间的关系,和java中的继承相似,子工程可以继承父工程中的配置信息,常见于依赖关系的继承。

作用:简化依赖配置,统一管理依赖

1
实现:<parent>...</parent>

image-20240311191546007

继承关系实现

① 创建maven模块 tlias-parent ,该工程为父工程,设置打包方式pom(默认jar)。

打包方式:

jar:普通模块打包,springboot项目基本都是jar包(内嵌tomcat运行)

war:普通web程序打包,需要部署在外部的tomcat服务器中运行

pom:父工程或聚合工程,该模块不写代码,仅进行依赖管理

1
2
3
4
5
6
7
8
9
10
11
12
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.7.5</version>
<relativePath/>
</parent>

<groupId>com.itheima</groupId>
<artifactId>tlias-parent</artifactId>
<version>1.0-SNAPSHOT</version>
<packaging>pom</packaging>

② 在子工程的pom.xml文件中,配置继承关系

image-20240311194125306

1
2
3
4
在子工程中,配置了继承关系之后,坐标中的groupId是可以省略的,因为会自动继承父工程的 。

relativePath指定父工程的pom文件的相对位置(如果不指定,将从本地仓库/远程仓库查找该工程)。

image-20240311192123449

③ 在父工程中配置各个工程共有的依赖(子工程会自动继承父工程的依赖)。

image-20240311192033341

1
2
3
4
5
6
7
<dependencies>    
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.24</version>
</dependency>
</dependencies>

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

image-20240311194512198

版本锁定

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

image-20240311195137523

image-20240311195305186

image-20240311195401893

image-20240311200349898

1
2
3
<dependencyManagement> 与 <dependencies>的区别是什么?
<dependencies> 是直接依赖,在父工程配置了依赖,子工程会直接继承下来。
<dependencyManagement> 是统一管理依赖版本,不会直接依赖,还需要在子工程中引入所需依赖(无需指定版本)

聚合

image-20240311200842420

要把几个模块全部安装到本地之后才能打包

1
2
3
4
5
6
聚合
将多个模块组织成一个整体,同时进行项目的构建。
聚合工程
一个不具有业务功能的“空”工程(有且仅有一个pom文件)
作用
快速构建项目(无需根据依赖关系手动构建,直接在聚合工程上构建即可)
1
maven中可以通过 <modules> 设置当前聚合工程所包含的子模块名称
1
2
3
4
5
6
7
8
<!--聚合-->父工程(聚合工程)

<modules>
<module>../tlias-pojo</module>
<module>../tlias-utils</module>
<module>../tlias-web-management</module>
</modules>

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

总结

作用

  • 聚合用于快速构建项目
  • 继承用于简化依赖配置、统一管理依赖

相同点:

  • 聚合与继承的pom.xml文件打包方式均为pom,可以将两种关系制作到同一个pom文件中
  • 聚合与继承均属于设计型模块,并无实际的模块内容

不同点:

  • 聚合是在聚合工程中配置关系,聚合可以感知到参与聚合的模块有哪些
  • 继承是在子模块中配置关系,父模块无法感知哪些子模块继承了自己

私服

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

image-20240311201437607

image-20240311201447693

image-20240311201500467

配置优先级

image-20240311131236747

从上至下优先级

image-20240311131859933

命令行参数>java系统属性

Bean管理

Spring项目启动时,会把bean都创建好放到IOC容器当中,如果想要主动获取这些bean:

image-20240311133629292

image-20240311134105870

bean的获取

image-20240311134034393

在spring容器中,bean默认是单例的

作用域 说明
singleton 容器内同 名称 的 bean 只有一个实例(单例)(默认)
prototype 每次使用该 bean 时会创建新的实例(非单例)
request 每个请求范围内会创建新的实例(web环境中,了解)
session 每个会话范围内会创建新的实例(web环境中,了解)
application 每个应用范围内会创建新的实例(web环境中,了解)
1
2
3
4
5
6
@Scope("prototype")
@RestController
@RequestMapping("/depts")
public class DeptController {
}

注意事项

默认singleton的bean,在容器启动时被创建,可以使用@Lazy注解来延迟初始化(延迟到第一次使用时)。

prototype的bean,每一次使用该bean的时候都会创建一个新的实例。

实际开发当中,绝大部分的Bean是单例的,也就是说绝大部分Bean不需要配置scope属性。

第三方bean

1
2
3
4
5
@Component
@Controller
@Service
@Repository

如果要管理的bean对象来自于第三方(不是自定义的,是无法用@Component以及衍生注解声明bean的,就是需要用到@Bean注解)

image-20240311141158692

一、用启动类,不建议

二、用第三方bean对象

用配置类声明第三方bean对象

image-20240311142532205

通过 @Bean注解的name/value属性指定bean名称,如果没有指定,默认是方法名

SpringBoot原理

起步依赖

Maven存在一个依赖传递,只要提供一个起步依赖

自动配置

SpringBoot的自动配置就是当spring容器启动之后,一些配置类,bean对象就自动的存入了IOC容器中,不需要我们手动去声明

当想要实现从另外一个项目引入

image-20240311145118080

springboot只能扫描到启动类及其子包,扫描不到其他的包

方案一:ComponentScan(使用繁琐,效率低)

1
2
3
4
5
@ComponentScan({"com.example","com.itheima"})
@SpringBootApplication
public class SpringbootWebConfig2Application {
}

image-20240311145621804

方案二:@Import 导入。

使用@Import导入的类会被Spring加载到IOC容器中,导入形式主要有以下几种

  • 导入 普通类
  • 导入 配置类
  • 导入 ImportSelector 接口实现类

@EnableXxxx注解,封装@Import注解

image-20240311150440558

image-20240311150642205

image-20240311150707450

源码跟踪

@SpringBootApplication

——->

1
2
3
4
5
6
7
8
9
10
@SpringBootConfigration
这个注解只是封装了一个注解@Configuration

@ComponentScan
用来scan子包之类的;组件扫描,默认扫描当前引导类所在包及其子包。


@EnableAutoConfiguration
自动配置的核心注解--》底层封装的@import注解
--》@Import(AutoConfigurationTmportSelector.class)

image-20240311155050608

@Conditional

以conditional开头的注解都是条件装配的注解

作用:按照一定的条件进行判断,在满足给定条件后才会注册对应的bean对象到Spring IOC容器中。

位置:方法、类

@Conditional 本身是一个父注解,派生出大量的子注解:

  • @ConditionalOnClass:判断环境中是否有对应字节码文件,才注册bean到IOC容器。
  • @ConditionalOnMissingBean:判断环境中没有对应的bean(类型 或 名称) ,才注册bean到IOC容器。
  • @ConditionalOnProperty:判断配置文件中有对应属性和值,才注册bean到IOC容器。

image-20240311155517846

image-20240311155831161

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
@Bean
@ConditionalOnClass(name = "io.jsonwebtoken.Jwts") //当前环境存在指定的这个类时,才声明该bean
public HeaderParser headerParser(){...}


@Bean
@ConditionalOnMissingBean //当不存在当前类型的bean时,才声明该bean
public HeaderParser headerParser(){...}
//指定的类型(value属性)或者 名称(name属性)
//通常用来设置一个默认的bean对象

@Bean
@ConditionalOnProperty(name = "name",havingValue = "itheima") //配置文件中存在对应的属性和值,才注册bean到IOC容器。
public HeaderParser headerParser(){...}
//name表示配置项的名字,havingValue表示配置项的值

image-20240311160715872

image-20240311160922672

自定义starter

image-20240311162501274

需求:自定义aliyun-oss-spring-boot-starter,完成阿里云OSS操作工具类 AliyunOSSUtils 的自动配置。

目标:引入起步依赖引入之后,要想使用阿里云OSS,注入 AliyunOSSUtils直接使用即可。

image-20240311162756249

image-20240311162942568

不想听了

总结

三层架构

image-20240311164359672

image-20240311164625979

image-20240311164645808

image-20240311164810304

表单校验、拦截

image-20240309155641073

会话技术

会话:

用户打开浏览器,访问web服务器的资源,会话建立,直到有一方断开连接,会话结束。在一次会话中可以包含多次请求和响应。

会话跟踪:

一种维护浏览器状态的方法,服务器需要识别多次请求是否来自于同一浏览器,以便在同一次会话的多次请求间共享数据。

会话跟踪方案:

客户端会话跟踪技术:Cookie

image-20240309172423138

优点:HTTP协议中支持的技术

缺点:
移动端APP无法使用Cookie
不安全,用户可以自己禁用Cookie
Cookie不能跨域

服务端会话跟踪技术:Session

image-20240309174401554

优点:存储在服务端,安全

缺点:

​ 服务器集群环境下无法直接使用Session

​ Cookie的缺点

令牌技术

image-20240309180204979

image-20240309160120522

JWT令牌

image-20240310131306339

过滤器Filter

概念:filter 过滤器,是javaweb三大组件(Servlet,filter,listener)之一;

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

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

image-20240310140809867

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

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

1
2
@WebFilter(urlPatterns = "/*")
表示全部的请求都被拦截

image-20240310142852164

doFilter

Filter快速入门
定义:实现Filter接口
配置:@WebFilter(urlPatterns=”/*”)
@ServletComponentScan

详解(执行流程、拦截路径,过滤器链)

执行流程

1
chain.doFilter(request,response);

l放行后访问对应资源,资源访问完成后,还会回到Filter中吗?==会==

l如果回到Filter中,是重新执行还是执行放行后的逻辑呢?==执行放行后逻辑==

image-20240310151225803

拦截路径

Filter 可以根据需求,配置不同的拦截资源路径:

拦截路径 urlPatterns值 含义
拦截具体路径 /login 只有访问 /login 路径时,才会被拦截
目录拦截 /emps/* 访问/emps下的所有资源,都会被拦截
拦截所有 /* 访问所有资源,都会被拦截

image-20240310151718949

过滤器链

介绍:一个web应用中,可以配置多个过滤器,这多个过滤器酒形成了一个过滤器链。

image-20240310152048450

image-20240310152242361

image-20240310152925112

登录校验filter

image-20240310153719014

请求头中携带令牌(token)

image-20240310154635261

1. 获取请求url
1
String url = req.getRequestURL().toString();

拦截器Interceptor

简介和快速入门

概念:是一种动态拦截方法调用的机制,类似于过滤器。Spring框架中提供的,用来动态拦截控制器方法的执行。

作用:拦截请求,在指定的方法调用前后,根据业务需要执行预先设定的代码。

image-20240310161305917

image-20240310161913186

image-20240310162622454

详解

拦截器-拦截路径

image-20240310162758884

拦截路径 含义 举例
/* 一级路径 能匹配/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

执行流程

image-20240310162921714

登录校验- Interceptor

image-20240310162943382

出现异常,该如何处理?

方案一:在Controller的方法中进行try…catch处理

方案二:全局异常处理器

image-20240310163515596

image-20240310163945488

事务管理和AOP

事务管理

概念

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

操作

开启事务(一组操作开始前,开启事务):start transaction / begin;

提交事务 (这组操作全部成功后,提交事务):commit;

回滚事务(中间任何一个操作出现异常,回滚事务):rollback;

Spring事务管理

image-20240310183459564

@Transactional

image-20240310183634814

image-20240310183751109

事务进阶

rollbackFor–回滚

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

image-20240310184253693

propagation–传播

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

image-20240310185655780

属性值 含义
REQUIRED 【默认值】需要事务,有则加入,无则创建新事务
REQUIRES_NEW 需要新事务,无论有无,总是创建新事务
SUPPORTS 支持事务,有则加入,无则在无事务状态中运行
NOT_SUPPORTED 不支持事务,在无事务状态下运行,如果当前存在已有事务,则挂起当前事务
MANDATORY 必须有事务,否则抛异常
NEVER 必须没事务,否则抛异常

AOP

AOP概述(Aspect Oriented Programming)

面向切面编程,面向方向编程,面向特定方法编程

动态代理技术是实现面向切面编程最主流的方法

场景:案例部分功能运行较慢,定位执行耗时较长的业务方法,此时需要统计每一个业务方法的执行耗时。

image-20240310192516869

image-20240310192644685

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

优点:

    1. 在没有对于原始方法进行修改的同时,代码无侵入
    2. 减少重复代码
    3. 提高开发效率
    4. 维护比较方便
1
2
3
4
5
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-aop</artifactId>
</dependency>

image-20240311093129040

理解来说,就是把原始的方法进行包装,在这个AOP类中就可以定义在运行原始方法前运行什么操作。

AOP快速入门

AOP核心概念

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

一旦执行了AOP流程,执行对象的目标不是原来的对象,而是代理对象

image-20240310205017770

通知类型

image-20240310205142244以上也是切入点表达式,存在重复问题,需要将其抽取。

image-20240311100357714

public :表示在其他外部的切面类中也可以应用该表达式

private:在其他外部的切面类红也可以引用该表达式

image-20240311100628539

通知顺序

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

1.不同切面类中,默认按照切面类的类名字母排序:

​ 目标方法前的通知方法:字母排名靠前的先执行

​ 目标方法后的通知方法:字母排名靠前的后执行

2.在切面类上添加order注解

image-20240311101259010

切入点表达式

基础

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

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

常见形式:

1.execution(……):根据方法的签名来匹配

2.@annotation(……) :根据注解匹配

1
execution(访问修饰符?  返回值  包名.类名.?方法名(方法参数) throws 异常?)

其中带 ? 的表示可以省略的部分

访问修饰符:可省略(比如: public、protected)

包名.类名: 可省略

可以省略但是不建议,不然会使得匹配的范围过大

throws 异常:可省略(注意是方法上声明抛出的异常,不是实际抛出的异常)

image-20240311101845730

image-20240311102223113

@annotation(……)

定义注解,这个注解起到一个标识的作用

image-20240311105248945

@annotation 切入点表达式,用于匹配标识有特定注解的方法。

image-20240311105423424

image-20240311105605500

连接点

可以被AOP控制的方法

在Spring中用JoinPoint抽象了连接点,用它可以获得方法执行时的相关信息,比如目标类名,方法名。

就是把之前的那些给抽象了

对于 @Around 通知,获取连接点信息只能使用 ProceedingJoinPoint

1
2
3
4
5
6
7
8
9
10
11
@Around("execution(* com.itheima.service.DeptService.*(..))")
public Object around(ProceedingJoinPoint joinPoint) throws Throwable {

String className = joinPoint.getTarget().getClass().getName(); //获取目标类名
Signature signature = joinPoint.getSignature(); //获取目标方法签名
String methodName = joinPoint.getSignature().getName(); //获取目标方法名
Object[] args = joinPoint.getArgs(); //获取目标方法运行参数
Object res = joinPoint.proceed(); //执行原始方法,获取返回值(环绕通知)
return res;
}

image-20240311110305088

1
2
3
4
5
6
7
8
9
@Before("execution(* com.itheima.service.DeptService.*(..))")
public void before(JoinPoint joinPoint) {

String className = joinPoint.getTarget().getClass().getName(); //获取目标类名
Signature signature = joinPoint.getSignature(); //获取目标方法签名
String methodName = joinPoint.getSignature().getName(); //获取目标方法名
Object[] args = joinPoint.getArgs(); //获取目标方法运行参数
}

AOP案例

步骤

image-20240311111119459

step1:自定义注解

image-20240311111347779

step2:编写切面类

image-20240311111641547

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
//LogAspect.java
@Slf4j
@Component
@Aspect //切面类
public class LogAspect {

@Autowired
private HttpServletRequest request;

@Autowired
private OperateLogMapper operateLogMapper;

@Around("@annotation(com.itheima.anno.Log)")
public Object recordLog(ProceedingJoinPoint joinPoint) throws Throwable {
//操作人ID - 当前登录员工ID
//获取请求头中的jwt令牌, 解析令牌
String jwt = request.getHeader("token");
Claims claims = JwtUtils.parseJWT(jwt);
Integer operateUser = (Integer) claims.get("id");

//操作时间
LocalDateTime operateTime = LocalDateTime.now();

//操作类名
String className = joinPoint.getTarget().getClass().getName();

//操作方法名
String methodName = joinPoint.getSignature().getName();

//操作方法参数
Object[] args = joinPoint.getArgs();
String methodParams = Arrays.toString(args);

long begin = System.currentTimeMillis();
//调用原始目标方法运行
Object result = joinPoint.proceed();
long end = System.currentTimeMillis();

//方法返回值
String returnValue = JSONObject.toJSONString(result);

//操作耗时
Long costTime = end - begin;


//记录操作日志
OperateLog operateLog = new OperateLog(null,operateUser,operateTime,className,methodName,methodParams,returnValue,costTime);
operateLogMapper.insert(operateLog);

log.info("AOP记录操作日志: {}" , operateLog);

return result;
}

}

image-20240311112626488

什么是Mybatis?

数据层又叫做持久层

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

Mybatis入门

mybatis快速入门

使用Mybatis查询所有用户数据

image-20240307163841670

Mapper层:mybatis的接口层。加mapper注释,数据访问层dao层的接口,

要执行语句那句select语句时,只需要使用list方法,就会默认的调用这个语句,sql语句的访问结果就会默认的封装到这个方法里

step1:准备数据库

运行sql语句创建数据库

step2:创建springboot项目,点上mybatis之类的tool

step3:连接数据库

image-20240307171742192

step4:创建实体类pojo

可以直接用mybatis-generator生成

image-20240307173829357

step5:创建mapper接口层

@Mapper//在运行时,会自动生成该接口的实现类对象(代理对象),并且将该对象交给IOC容器管理

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
package com.ljy.demo5.mapper;

import com.ljy.demo5.Pojo.User;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Select;

import java.util.List;

@Mapper//在运行时,会自动生成该接口的实现类对象(代理对象),并且将该对象交给IOC容器管理
public interface UserMapper {
//查询全部的用户信息

@Select("select * from user")
public List<User> list();
}

image-20240307173836328

step6:测试

在test项目里测试

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
@SpringBootTest//springboot整合单元测试的注解
class Demo5ApplicationTests {


@Autowired
private UserMapper userMapper;

@Test
public void testListUser(){
List<User> list = userMapper.list();
list.stream().forEach(user -> {
System.out.println(user);
});
}

}

输出结果

image-20240307173935097

JDBC介绍

java database connectivity,就是使用java语言操作关系型数据库的一套API,这是一套规范,sun公司提供的

各个厂商提供jdbc的实现,这个叫做jdbc的驱动、数据库的驱动

image-20240307174626361

image-20240307175035561

数据库连接池

数据库连接池是一个容器,负责分配、管理数据库连接(connection)

它允许应用程序重复使用一个现有的数据库连接,而不是再重新创建一个新的

释放空闲时间超过最大空闲时间的连接,来避免因为没有释放连接而引起的数据库连接遗漏。

image-20240307175453352

image-20240307175644217

image-20240307175738544

切换Druid数据库连接池

image-20240307175836059

1
2
3
4
5
6
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid-spring-boot-starter</artifactId>
<version>1.2.8</version>
</dependency>
pom.xml
1
2
3
4
spring.datasource.druid.driver-class-name=com.mysql.cj.jdbc.Driver
spring.datasource.druid.url=jdbc:mysql://localhost:3306/mybatis
spring.datasource.druid.username=root
spring.datasource.druid.password=1234

小结

1.数据库连接池

l是一个容器,负责分配、管理数据库连接(Connection)

l优势:资源复用、提升系统响应速度

l接口:DataSource

l产品:C3P0、DBCP、Druid、Hikari

Lombok

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

image-20240307180112001

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

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

Mybatis基础增删改查

准备

按照之前的准备

image-20240307201152408

删除

按照ID删除数据

@Delete注释

占位符 #{id}

1
2
@Delete("delete from emp where id = #{id}")
public void delete(Integer id);
1
2
3
4
5
6
7
8
@Mapper
public interface EmpMapper {

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


}

日志

image-20240307202608039

image-20240307202628672

预编译sql语句

  • 性能更高
  • 更安全(防止SQL注入)

image-20240307202803149

SQL注入

通过操作输入的数据来修改事先定义好的SQL语句,以达到执行代码对服务器进行攻击的方法。

image-20240307203932583

image-20240307204228284

插入

1
2
3
4
//新增员工
@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
5
6
7
@Test
public void testInsert(){
Emp emp = new Emp();
emp.setUsername("Tom");
emp.setName("汤姆");

}

主键返回@Options(keyProperty=”id”)

描述:在数据添加成功后,需要获取插入数据库数据的主键。如:添加套餐数据时,还需要维护套餐菜品关系表数据。

image-20240307205557662

更新(修改)

1
2
3
4
//更新员工
@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);
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
@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.setUpdateTime(LocalDateTime.now());
emp.setDeptId(1);

//执行更新员工操作
empMapper.update(emp);
}

查询

1
2
3
@Select("select * from emp where id = #{id}")
public Emp getById(Integer id);

1
2
3
4
5
@Test
public void testGetById(){
Emp emp = empMapper.getById(18);
System.out.println(emp);
}

image-20240307210950229

数据封装

image-20240307211215522

解决一

image-20240307213019502

1
2
3
4
//方案三: 开启mybatis的驼峰命名自动映射开关 --- a_cloumn ------> aColumn
//根据ID查询员工
@Select("select * from emp where id = #{id}")
public Emp getById(Integer id);

MybatisXML映射文件

image-20240307215655415

xml映射文件

Mybatis动态SQL

随着用户的输入或者外部的变化而变化SQL语句,我们称为动态SQL

if

1
2
3
<if>:用于判断条件是否成立。使用test属性进行条件判断,如果条件为true,则拼接SQL。

<where>:where 元素只会在子元素有内容的情况下才插入where子句。而且会自动去除子句的开头的AND 或OR。

image-20240308165208370

foreach

Springboot案例

image-20240309135242851

image-20240309135953209

image-20240309140016098

image-20240309140549167

分页参数

文件上传

表单项

文件上传

数据库设计

Mysql概述

分类 全称 说明
DDL Data Definition Language 数据定义语言,用来定义数据库对象(数据库,表,字段)
DML Data Manipulation Language 数据操作语言,用来对数据库表中的数据进行增删改
DQL Data Query Language 数据查询语言,用来查询数据库中表的记录
DCL Data Control Language 数据控制语言,用来创建数据库用户、控制数据库的访问权限

image-20240307132823507

数据库设计-DDL

约束 描述 关键字
非空约束 限制该字段值不能为null not null
唯一约束 保证字段的所有数据都是唯一、不重复的 unique
主键约束 主键是一行数据的唯一标识,要求非空且唯一 primary key
默认约束 保存数据时,如果未指定该字段值,则采用默认值 default
外键约束 让两张表的数据建立连接,保证数据的一致性和完整性 foreign key

MySQL中的数据类型有很多,主要分为三类:数值类型、字符串类型、日期时间类型。

数据表

image-20240307135013214

create_time:记录的是当前这条数据插入的时间。 update_time:记录当前这条数据最后更新的时间

image-20240307135215533

表(创建、查询、修改、删除)

多表设计

数据库操作

数据库操作-DML

DML的英文全称是data Manipulation Language(数据操作语言),用来对数据库中表的数据记录进行增删改查操作

1
2
3
添加数据(INSERT)
修改数据(UPDATE)
删除数据(DELETE)

INSERT

指定字段添加数据:insert into 表名 (字段名1, 字段名2) values (值1, 值2);

全部字段添加数据:insert into 表名 values (值1, 值2, …);

批量添加数据(指定字段):insert into 表名 (字段名1, 字段名2) values (值1, 值2), (值1, 值2);

批量添加数据(全部字段):insert into 表名 values (值1, 值2, …), (值1, 值2, …);

update

修改数据:update 表名 set 字段名1 = 值1 , 字段名2 = 值2 , …. [ where 条件 ] ;

修改语句的条件可以有,也可以没有,如果没有条件,则会修改整张表的所有数据。

DELETE

删除数据:delete from 表名 [ where 条件 ];

1.DELETE 语句的条件可以有,也可以没有,如果没有条件,则会删除整张表的所有数据。

2.DELETE 语句不能删除某一个字段的值(如果要操作,可以使用UPDATE,将该字段的值置为NULL)。

数据库操作-DQL SELECT

DQL英文全称是Data Query Language(数据查询语言),用来查询数据库表中的记录。

查询多个字段:select 字段1, 字段2, 字段3 from 表名;

查询所有字段(通配符):select * from 表名;

设置别名:select 字段1 [ as 别名1 ] , 字段2 [ as 别名2 ] from 表名;

去除重复记录:select distinct 字段列表 from 表名;

事务

介绍

事务 是一组操作的集合,它是一个不可分割的工作单位。事务会把所有的操作作为一个整体一起向系统提交或撤销操作请求,即这些操作 要么同时成功,要么同时失败。

1
2
3
开启事务:start transaction; / begin ;
提交事务:commit;
回滚事务:rollback;

四大特性(ACID)

image-20240307152341854

多表查询

一对一

一对多

多对对

数据库优化

索引

SQL优化

image-20240305150715516

JS

1.JS引入方式

2.变量

JavaScript 中用 var 关键字(variable 的缩写)来声明变量 。

JavaScript 是一门弱类型语言,变量可以存放不同类型的值 。

变量名需要遵循如下规则:

​ Ø组成字符可以是任何字母、数字、下划线(_)或美元符号($)

​ Ø数字不能开头

​ Ø建议使用驼峰命名

ECMAScript 6 新增了 let 关键字来定义变量。它的用法类似于 var,但是所声明的变量,只在 let 关键字所在的代码块内有效,且不允许重复声明。

ECMAScript 6 新增了 const 关键字,用来声明一个只读的常量。一旦声明,常量的值就不能改变。

•var:声明变量,全局作用域/函数作用域,允许重复声明

• let:声明变量,块级作用域,不允许重复声明

• const:声明常量,一旦声明,常量的值不能改变

3.数据类型

JavaScript中分为:原始类型 和 引用类型

image-20240306105949534

var 变量名 = new Array(元素列表);

image-20240306110748714

4.BOW

Browser Object Model 浏览器对象模型,允许JavaScript与浏览器对话, JavaScript 将浏览器的各个组成部分封装为对象。

location地址对象:就是那个框

属性

history:对 History 对象的只读引用。请参阅 History 对象

location:用于窗口或框架的 Location 对象。请参阅 Location 对象

navigator:对 Navigator 对象的只读引用。请参阅 Navigator 对象

方法

alert():显示带有一段消息和一个确认按钮的警告框。

confirm():显示带有一段消息以及确认按钮和取消按钮的对话框。

setInterval():按照指定的周期(以毫秒计)来调用函数或计算表达式。

setTimeout():在指定的毫秒数后调用函数或计算表达式。

5.DOM(概念:Document Object Model ,文档对象模型)

image-20240306111613344

6.事件监听

事件:HTML事件是发生在HTML元素上的 “事情”。比如:

1
2
3
4
5
按钮被点击

鼠标移动到元素上

按下键盘按键

事件监听:JavaScript可以在事件被侦测到时 执行代码。

事件绑定

方式一:通过 HTML标签中的事件属性进行绑定

1
2
3
4
5
6
7
<input type="button" onclick="on()" value="按钮1">

<script>
    function on(){
        alert('我被点击了!');
    }
</script>

方式二:通过 DOM 元素属性绑定

1
2
3
4
5
6
7
8
9
10
11
<input type="button" id="btn" value="按钮2">

<script>

document.getElementById('btn').onclick=function(){

alert('我被点击了!');

}

</script>

常见事件

image-20240306112610533

7.Vue

Vue 是一套前端框架,免除原生JavaScript中的DOM操作,简化书写。

基于MVVM(Model-View-ViewModel)思想,实现数据的双向绑定,将编程的关注点放在数据上。

官网: https://v2.cn.vuejs.org/

image-20240306112707334

Vue快速入门

image-20240306112754269

常用指令

指令:HTML 标签上带有 v- 前缀 的特殊属性,不同指令具有不同含义。例如:v-if,v-for…

常用指令

指令 作用
v-bind 为HTML标签绑定属性值,如设置 href , css样式等
v-model 在表单元素上创建双向数据绑定
v-on 为HTML标签绑定事件
v-if 条件性的渲染某元素,判定为true时渲染,否则不渲染
v-else-if
v-else
v-show 根据条件展示某元素,区别在于切换的是display属性的值
v-for 列表渲染,遍历容器的元素或者对象的属性
指令 作用
v-bind 为HTML标签绑定属性值,如设置 href , css样式等
v-model 在表单元素上创建双向数据绑定

通过v-bind或者v-model绑定的变量,必须在数据模型中声明。

image-20240306113353512

image-20240306113419926

生命周期

生命周期:指一个对象从创建到销毁的整个过程。

生命周期的八个阶段:每触发一个生命周期事件,会自动执行一个生命周期方法(钩子)。

状态 阶段周期
beforeCreate 创建前
created 创建后
beforeMount 挂载前
mounted 挂载完成
beforeUpdate 更新前
updated 更新后
beforeDestroy 销毁前
destroyed 销毁后

image-20240306114312596

生命周期的八个阶段:每触发一个生命周期事件,会自动执行一个生命周期方法(钩子)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
<script>
    new Vue({
        el: "#app",
        data: {
           
        },
        mounted() {
            console.log("Vue挂载完毕,发送请求获取数据");
        },
        methods: {
           
        },
    })
</script>

mounted:挂载完成,Vue初始化成功,HTML页面渲染成功。(发送请求到服务端,加载数据)

Maven

Maven是apache旗下的一个开源项目,是一款用于管理和构建java项目的工具。

基于项目对象模型(POM)的概念,通过一小段描述信息来管理项目的构建。

作用

依赖管理:方便快捷的管理项目依赖的资源(jar包),避免版本冲突问题

统一项目结构:提供标准、统一的项目结构

项目构建:标准跨平台(Linux、Windows、MacOS)的自动化项目构建方式

清理、编译、测试、打包、发布

image-20240306132942342

Maven概述

image-20240306134710518

image-20240306134742641

Maven坐标

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

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

Maven 坐标主要组成

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

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

version:定义当前项目版本号

image-20240306135618173

依赖配置

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

1
2
3
4
5
6
7
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>
依赖具有传递性

直接依赖:在当前项目中通过依赖配置建立的依赖关系

间接依赖:被依赖的资源如果依赖其他资源,当前项目间接依赖其他资源

image-20240306140113368

排除依赖

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

image-20240306140209596

依赖范围

依赖的jar包,默认情况下,可以在任何地方使用。可以通过

1
<scope>…</ scope > 

设置其作用范围。

作用范围:

image-20240306140857607

image-20240306140907131

scope****值 主程序 测试程序 打包(运行) 范例
compile(默认) Y Y Y log4j
test - Y - junit
provided Y Y - servlet-api
runtime - Y Y jdbc驱动

生命周期

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

image-20240306141128223

image-20240306141920091

Maven中有3套相互独立的生命周期:

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

  • clean:清理工作。
  • default:核心工作,如:编译、测试、打包、安装、部署等。
  • site:生成报告、发布站点等。
1
2
3
4
5
clean:移除上一次构建生成的文件
compile:编译项目源代码
test:使用合适的单元测试框架运行测试(junit)
package:将编译后的文件打包,如:jar、war等
install:安装项目到本地仓库

image-20240306142550365

image-20240306142605065

Spring

image-20240306142800941

Spring Framework配置比较繁琐,入门的难度比较大

Sprint Boot简化配置,快速入门

SpringBootWeb入门

Controller类

image-20240306143624478

image-20240306143813629

HTTP协议

HTTP-概述

基于请求-响应模型:一次请求对应一次响应

基于TCP协议:面向连接、安全

HTTP协议是无状态的协议:对于事务处理没有记忆能力。每次请求-响应都是独立的。

​ 缺点:多次请求间不能共享数据

​ 优点:速度快

image-20240306143950651

Hyper Text Transfer Protocol,超文本传输协议,规定了浏览器和服务器之间数据传输的规则。

HTTP-请求协议

get

post

image-20240306214453971

image-20240306144631222

image-20240306144652867

image-20240306144754893

HTTP-响应协议

image-20240306144904417

200 客户端请求成功。
404 请求资源不存在,般是URL输入有误,或者网站资源被删除了。
500 服务器发生不可预期的错误。

HTTP-协议解析

Web服务器-Tomcat

Web服务器 对HTTP协议操作进行封装,简化web程序开发

部署web项目,对外提供网上信息浏览服务。

Tomcat简介

一个轻量级的web服务器,支持servlet、jsp等少量javaEE规范。

也被称为web容器、servlet容器。

  • 概念: 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/

image-20240306150115020

小结

  1. 起步依赖

image-20240306150153737

  1. 内嵌Tomcat服务器

image-20240306150215953

Web后端开发-请求响应

image-20240306150713034

image-20240306150724281

image-20240306150855385

请求

Postman

前后端分离开发

当前最为流行的开发模式:前后端分离

image-20240306151151217

Postman

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

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

简单参数

原始方式

获取请求参数,需要HttpServletRequest 对象手动获取

image-20240306151429294

SpringBoot方式

简单参数:参数名与形参变量名相同,定义形参即可接收参数。

1
2
3
4
5
@RequestMapping("/simpleParam")
public String simpleParam(String name , Integer age){
System.out.println(name+" : "+age);
return "OK";
}

简单参数:如果方法形参名称与请求参数名称不匹配,可以使用 @RequestParam 完成映射。

1
2
3
4
5
6
@RequestMapping("/simpleParam")
public String simpleParam(@RequestParam(name = "name") String username , Integer age){
System.out.println(username + " : " + age);
return "OK";
}

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

实体参数

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

image-20240306152052414

1
2
3
4
5
6
7
8
9
10
11
12
@RequestMapping("/simplePojo")
public String simplePojo(User user){
System.out.println(user);
return "OK";
}

// 这个放在Pojo文件夹里
public class User {
private String name;
private Integer age;
}

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

image-20240306152643855

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
@RequestMapping("/complexPojo")
public String complexPojo(User user){
System.out.println(user);
return "OK";
}
public class User {
private String name;
private Integer age;
private Address address;
}
public class Address {
private String province;
private String city;
}


数组集合参数

数组参数

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

image-20240306153107242

1
2
3
4
5
@RequestMapping("/arrayParam")
public String arrayParam(String[] hobby){
System.out.println(Arrays.toString(hobby));
return "OK";
}

集合参数@RequestParam

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

image-20240306153320104

1
2
3
4
5
6
@RequestMapping("/listParam")
public String listParam(@RequestParam List<String> hobby){
System.out.println(hobby);
return "OK";
}

总结

==数组:请求参数名与形参中数组变量名相同,可以直接使用数组封装==

==集合:请求参数名与形参中集合变量名相同,通过@RequestParam绑定参数关系==

日期参数@DateTimeFormat

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

image-20240306153733135

1
2
3
4
5
6
@RequestMapping("/dateParam")
public String dateParam(@DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss") LocalDateTime updateTime){
System.out.println(updateTime);
return "OK";
}

Json参数

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

image-20240306154922588

1
2
3
4
5
6
7
8
9
10
11
12
13
14
@RequestMapping("/jsonParam")
public String jsonParam(@RequestBody User user){
System.out.println(user);
return "OK";
}
public class User {
private String name;
private Integer age;
private Address address;
}
public class Address {
private String province;
private String city;
}

路径参数

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

1
2
3
4
5
6
@RequestMapping("/path/{id}/{name}")
public String pathParam2(@PathVariable Integer id, @PathVariable String name){
System.out.println(id+ " : " +name);
return "OK";
}

image-20240306202824520

响应

@ResponseBody

位置:Controller类上/方法上

作用:将方法返回值直接响应,若返回值类型是 实体对象/集合 ,转JSON格式响应

说明:@RestController = @Controller + @ResponseBody ;

image-20240306204830544

统一响应结果

如果一个个的响应,不方便管理和维护

image-20240306204605470

分层解耦

三层架构

image-20240306205013500

controller:控制层,接收前端发送的请求,对请求进行处理,并响应数据。

service:业务逻辑层,处理具体的业务逻辑。

dao:数据访问层(Data Access Object)(持久层),负责数据访问操作,包括数据的增、删、改、查。

可能有很多类型的数据,比如是xml的、数据库的、或者是别人给的

image-20240306205150673

定义Dao层的接口,增强扩展性

image-20240307112932230

控制反转:

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

依赖注入:

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

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

1
1: Service层和Dao层的实现类,交给IOC容器管理

image-20240307113836905

如果要切换service,只需要把component修改了就行

image-20240307113929291

IOC详解

IOC对象 又称为bean对象

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

声明bean的时候,可以通过value属性指定bean的名字,如果没有指定,默认为类名首字母小写。

使用以上四个注解都可以声明bean,但是在springboot集成web开发中,声明控制器bean只能用@Controller。

Bean组件扫描

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

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

image-20240307115056516

Bean注入

@Autowired注解,默认是按照类型进行,如果存在多个相同类型的bean,将会报出如下错误:

image-20240307115609120

网络编程概述

什么是网络编程?

网络编程是指利用计算机网络实现程序之间通信的一种编程方式。在网络编程中,程序需要通过网络协议(如 TCP/IP)来进行通信,以实现不同计算机之间的数据传输和共享。

在网络编程中,通常有三个基本要素

①IP 地址:定位网络中某台计算机

②端口号port:定位计算机上的某个进程(某个应用)

③通信协议:通过IP地址和端口号定位后,如何保证数据可靠高效的传输,这就需要依靠通信协议了。

网络编程三要素

IP地址

①IP 地址用于唯一标识网络中的每一台计算机。在 Internet 上,使用 IPv4 或 IPv6 地址来表示 IP 地址。通常 IPv4 地址格式为 xxx.xxx.xxx.xxx,其中每个 xxx 都表示一个 8 位的二进制数(每一个xxx的取值范围是0-255),组合起来可以表示 2^32 个不同的 IP 地址。

②IPv4 地址的总数量是4294967296 个,但并不是所有的 IPv4 地址都可以使用。IPv4 地址被分为网络地址和主机地址两部分,前3个字节用于表示网络(省市区),最后1个字节用于表示主机(家门牌)。而一些 IP 地址被保留或者被私有机构使用,不能用于公网的地址分配。另外,一些 IP 地址被用作多播地址,仅用于特定的应用场景。因此实际上可供使用的 IPv4 地址数量要少于总数量,而且随着 IPv4 地址的逐渐枯竭,IPv6 地址已经开始逐渐普及,IPv6 地址数量更是相当巨大。

③IPv6使用16个字节表示IP地址(128位),这样就解决了网络地址资源数量不够的问题。IPv6 地址由 8 组 16 位十六进制数表示,每组之间用冒号分隔,如:3ffe:3201:1401:1280:c8ff:fe4d:db39:1984

④本机地址:127.0.0.1,主机名:localhost。

⑤192.168.0.0-192.168.255.255为私有地址,属于非注册地址,专门为组织机构内部使用。

IP地址相关的:域名与DNS

①域名

IP地址毕竟是数字标识,使用时不好记忆和书写,因此在IP地址的基础上又发展出一种符号化的地址方案,来代替数字型的IP地址。每一个符号化的地址都与特定的IP地址对应。这个与网络上的数字型IP地址相对应的字符型地址,就被称为域名。

目前域名已经成为互联网品牌、网上商标保护必备的要素之一,除了识别功能外,还有引导、宣传等作用。如:www.baidu.com

②DNS

在Internet上域名与IP地址之间是一对一(或者多对一)的,域名虽然便于人们记忆,但机器之间只能互相认识IP地址,它们之间的转换工作称为域名解析,域名解析需要由专门的域名解析服务器来完成,DNS(Domain Name System域名系统)就是进行域名解析的服务器,域名的最终指向是IP。

image-20240305094635174

端口号(port)

①在计算机中,不同的应用程序是通过端口号区分的。

②端口号是用两个字节(无符号)表示的,它的取值范围是0~65535,而这些计算机端口可分为3大类:

①公认端口:0~1023。被预先定义的服务通信占用(如:HTTP占用端口80,FTP占用端口21,Telnet占用端口23等)

②注册端口:1024~49151。分配给用户进程或应用程序。(如:Tomcat占用端口8080,MySQL占用端口3306,Oracle占用端口1521等)。

③动态/私有端口:49152~65535。

③通常情况下,服务器程序使用固定的端口号来监听客户端的请求,而客户端则使用随机端口连接服务器。

④IP地址好比每个人的地址(门牌号),端口好比是房间号。必须同时指定IP地址和端口号才能够正确的发送数据。接下来通过一个图例来描述IP地址和端口号的作用,如图所示:

通信协议

①通过计算机网络可以使多台计算机实现连接,位于同一个网络中的计算机在进行连接和通信时需要遵守一定的规则。就像两个人想要顺利沟通就必须使用同一种语言一样,如果一个人只懂英语而另外一个人只懂中文,这样就会造成没有共同语言而无法沟通。

②在计算机网络中,这些连接和通信的规则被称为网络通信协议,它对数据的传输格式、传输速率、传输步骤等做了统一规定,通信双方必须同时遵守才能完成数据交换。

③在计算机网络中,常用的协议有 TCP、UDP、HTTP、FTP 等。这些协议规定了数据传输的格式、传输方式和传输顺序等细节。其中,TCP(传输控制协议)是一种可靠的面向连接的协议,它提供数据传输的完整性保证;而 UDP(用户数据报协议)则是一种无连接的协议,传输效率高。在网络编程中,需要选取合适的协议类型来实现数据传输。

通信协议相关的:OSI参考模型(可以)

①世界上第一个网络体系结构由IBM公司提出(1974年,SNA),以后其他公司也相继提出自己的网络体系结构如:Digital公司的DNA,美国国防部的TCP/IP等,多种网络体系结构并存,其结果是若采用IBM的结构,只能选用IBM的产品,只能与同种结构的网络互联。

②为了促进计算机网络的发展,国际标准化组织ISO(International Organization for Standardization)于1977年成立了一个委员会,在现有网络的基础上,提出了不基于具体机型、操作系统或公司的网络体系结构,称为开放系统互连参考模型,即OSI/RM (Open System Interconnection Reference Model)。

==OSI模型把网络通信的工作分为7层,分别是物理层、数据链路层、网络层、传输层、会话层、表示层和应用层。OSI七层协议模型如图所示:==

image-20240305094745502

通信协议相关的:TCP/IP参考模型

①OSI参考模型的初衷是提供全世界范围的计算机网络都要遵循的统一标准,但是由于存在模型和协议自身的缺陷,迟迟没有成熟的产品推出。TCP/IP协议在实践中不断完善和发展取得成功,作为网络的基础,Internet的语言,可以说没有TCP/IP参考模型就没有互联网的今天。

TCP/IP,即Transmission Control Protocol/Internet Protocol的简写,中译名为传输控制协议/因特网互联协议,是Internet最基本的协议、Internet国际互联网络的基础。

③TCP/IP协议是一个开放的网络协议簇,它的名字主要取自最重要的网络层IP协议和传输层TCP协议。TCP/IP协议定义了电子设备如何连入因特网,以及数据如何在它们之间传输的标准。TCP/IP参考模型采用4层的层级结构,每一层都呼叫它的下一层所提供的协议来完成自己的需求,这4个层次分别是:网络接口层、互联网层(IP层)、传输层(TCP层)、应用层。

④OSI模型与TCP/IP模型的对应关系如图所示:

image-20240305094835205

OSI参考模型 与 TCP/IP参考模型 区别

​ ① OSI 参考模型是理论上的,而 TCP/IP 参考模型是实践上的。TCP/IP 参考模型被许多实际的协议(如 IP、TCP、HTTP 等)所支持和实现,而 OSI 参考模型则主要是作为理论框架和标准进行研究和讨论。

​ ②OSI 参考模型是由国际标准化组织提出的网络通信协议框架,其中分为 7 层,各层之间明确了功能的划分,从物理层到应用层,逐层向上升,每层只对自己下一层提供服务,并依次封装和解封数据。OSI 参考模型是一种理论上的协议框架,用于描述计算机系统间的通信原理和规范。

​ ③TCP/IP 参考模型(也称互联网参考模型)是实际应用中最广泛的协议框架。它将网络协议划分为 4 层:网络接口层、网络层、传输层和应用层。TCP/IP 参考模型与 OSI 参考模型之间有着相对应的层次结构,但是其中的每一层都是实际存在的协议,而不是纯粹的框架。TCP/IP 参考模型被广泛应用于互联网上,是计算机系统间进行通信的重要基础。

网络编程基础类

InetAddress类

① java.net.IntAddress类用来封装计算机的IP地址和DNS(没有端口信息),它包括一个主机名和一个IP地址,是java对IP地址的高层表示。大多数其它网络类都要用到这个类,包括Socket、ServerSocket、URL、DatagramSocket、DatagramPacket等

②常用静态方法

lstatic InetAddress getLocalHost() 得到本机的InetAddress对象,其中封装了IP地址和主机名

lstatic InetAddress getByName(String host) 传入目标主机的名字或IP地址得到对应的InetAddress对象,其中封装了IP地址和主机名(底层会自动连接DNS服务器进行域名解析)

③常用实例方法

1
2
3
public String getHostAddress() 获取IP地址

public String getHostName() 获取主机名/域名

获取InetAddress对象

1
InetAddress ia = InetAddress.getLocalHost();

获取本机的IP地址

1
2
String hostAddress = ia.getHostAddress();
System.out.println("本机IP地址:" + hostAddress); // 本机IP地址:192.168.137.101

获取本机的主机名称

1
2
String hostName = ia.getHostName();
System.out.println("本机的主机名:" + hostName); // 本机的主机名:MS-AQIGIVITIULB

通过域名来获取InetAddress对象

1
2
3
InetAddress ia2 = InetAddress.getByName("www.baidu.com");
System.out.println(ia2.getHostName()); // www.baidu.com
System.out.println(ia2.getHostAddress()); // 182.61.200.7

URL类

①URL是统一资源定位符,对可以从互联网上得到的资源的位置和访问方法的一种简洁的表示,是互联网上标准资源的地址。互联网上的每个文件都有一个唯一的URL,它包含的信息指出文件的位置以及浏览器应该怎么处理它。

②URL由4部分组成:协议、存放资源的主机域名、端口号、资源文件名。如果未指定该端口号,则使用协议默认的端口。例如HTTP协议的默认端口为80。在浏览器中访问网页时,地址栏显示的地址就是URL。

③URL标准格式为:<协议>://<域名或IP>:<端口>/<路径>。其中,<协议>://<域名或IP>是必需的,<端口>/<路径>有时可省略。如:https://www.baidu.com。

④为了方便程序员编程,JDK中提供了URL类,该类的全名是java.net.URL,该类封装了大量复杂的涉及从远程站点获取信息的细节,可以使用它的各种方法来对URL对象进行分割、合并等处理。

⑤URL类的构造方法:

1
URL url = new URL(“http://127.0.0.1:8080/oa/index.html?name=zhangsan#tip”);

⑥URL类的常用方法:

1
2
3
4
5
6
7
8
9
10
获取协议:url.getProtocol() 
获取域名:url.getHost()
获取默认端口:url.getDefaultPort()

获取端口:url.getPort()
获取路径:url.getPath()
获取资源:url.getFile()

获取数据:url.getQuery()
获取锚点:url.getRef()
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
// 创建URL类型的对象
URL url = new URL("http://www.baidu.com:8888/oa/index.html?name=zhangsan&password=123#tip");

// 获取URL中的信息
String protocol = url.getProtocol();
System.out.println("协议:" + protocol);

// 获取资源路径
String path = url.getPath();
System.out.println("资源路径:" + path);

// 获取默认端口(HTTP协议的默认端口是80)
int defaultPort = url.getDefaultPort();
System.out.println("默认端口:" + defaultPort);

// 获取当前的端口
int port = url.getPort();
System.out.println("当前端口号:" + port);

// 获取URL中的IP地址
String host = url.getHost();
System.out.println("主机地址:" + host);

// 获取URL准备传送的数据
String query = url.getQuery();
System.out.println("需要提交给服务器的数据:" + query);

// 获取锚点
String ref = url.getRef();
System.out.println("获取锚点:" + ref);

// 获取 资源路径 + 数据
String file = url.getFile();
System.out.println("资源路径+数据:" + file);

⑦使用URL类的openStream()方法可以打开到此URL的连接并返回一个用于从该连接读入的InputStream,实现最简单的网络爬虫

TCP与UDP协议

Socket套接字概述

①我们开发的网络应用程序位于应用层,TCP和UDP属于传输层协议,在应用层如何使用传输层的服务呢?在应用层和传输层之间,则是使用套接Socket来进行分离。

②套接字就像是传输层为应用层开的一个小口,应用程序通过这个小口向远程发送数据,或者接收远程发来的数据。而这个小口以内,也就是数据进入这个口之后,或者数据从这个口出来之前,是不知道也不需要知道的,也不会关心它如何传输,这属于网络其它层次工作。

③Socket实际是传输层供给应用层的编程接口。Socket就是应用层与传输层之间的桥梁。使用Socket编程可以开发客户机和服务器应用程序,可以在本地网络上进行通信,也可通过Internet在全球范围内通信。

④TCP协议和UDP协议是传输层的两种协议。Socket是传输层供给应用层的编程接口,所以Socket编程就分为TCP编程和UDP编程两类。

image-20240305104057960

TCP协议

①使用TCP协议,须先建立TCP连接,形成传输数据通道,似于拨打电话

②传输前,采用“三次握手”方式,属于点对点通信,是面向连接的,效率低。

③仅支持单播传输,每条TCP传输连接只能有两个端点(客户端、服务端)。

④两个端点的数据传输,采用的是“字节流”来传输,属于可靠的数据传输。

⑤传输完毕,需释放已建立的连接,开销大,速度慢,适用于文件传输、邮件等。

TCP协议的三次握手(通道建立)

TCP(传输控制协议)是一种面向连接的、可靠的传输层协议。它使用三次握手来建立连接,以确保数据在两个设备之间可靠地传输。

三次握手的过程如下:

  1. ==客户端发送 SYN(同步)数据包。这个数据包包含客户端的初始序列号(ISN)。==

  2. ==服务器收到 SYN 数据包后,发送 SYN-ACK(同步确认)数据包。这个数据包包含服务器的初始序列号(ISN)和对客户端 ISN 的确认号(ACK)。==

  3. ==客户端收到 SYN-ACK 数据包后,发送 ACK(确认)数据包。这个数据包包含对服务器 ISN 的确认号(ACK)。==

三次握手完成后,客户端和服务器就可以开始交换数据了。

三次握手的意义:

三次握手可以确保数据在两个设备之间可靠地传输。它可以防止以下情况的发生:

不会丢失:如果没有三次握手,客户端和服务器可能会同时发送数据,导致数据丢失。

不会重复:如果没有三次握手,客户端和服务器可能会重复发送数据,导致数据重复。

不会乱序:如果没有三次握手,客户端和服务器可能会乱序发送数据,导致数据乱序。

image-20240305104418462

TCP协议的四次挥手(通道关闭)

使用四次挥手来关闭连接,以确保数据在两个设备之间可靠地传输。

四次挥手的过程如下:

  1. 客户端发送 FIN(结束)数据包。这个数据包表示客户端已经完成数据传输,并希望关闭连接。

  2. 服务器收到 FIN 数据包后,发送 ACK(确认)数据包。这个数据包表示服务器已经收到客户端的 FIN 数据包,并同意关闭连接。

  3. 服务器发送 FIN 数据包。这个数据包表示服务器已经完成数据传输,并希望关闭连接。

  4. 客户端收到 FIN 数据包后,发送 ACK(确认)数据包。这个数据包表示客户端已经收到服务器的 FIN 数据包,并同意关闭连接。四次挥手完成后,客户端和服务器之间的连接就关闭了。

四次挥手的意义

四次挥手可以确保数据在两个设备之间可靠地传输。它可以防止以下情况的发生:

如果没有四次挥手,客户端和服务器可能会同时关闭连接,导致数据丢失。

如果没有四次挥手,客户端和服务器可能会重复发送数据,导致数据重复。

如果没有四次挥手,客户端和服务器可能会乱序发送数据,导致数据乱序。

image-20240305104523223

UDP协议

①采用数据报(数据、源、目的)的方式来传输,无需建立连接,类似于发短信。

②每个数据报的大小限制在64K内,超出64k可以分为多个数据报来发送。

③发送不管对方是否准备好,接收方即使收到也不确认,因此属于不可靠的。

④可以广播发送,也就是属于一对一、一对多和多对一连接的通信协议。

⑤发送数据结束时无需释放资源,开销小,速度快,适用于视频会议、直播等。

image-20240305104235110

基于TCP协议的编程

TCP协议编程概述

①socket是一种进程间的数据交换机制,利用套接字(Socket)开发网络应用程序早已被广泛的采用,以至于成为事实上的标准。

②在网络通讯中,第一次主动发起通讯的程序被称作客户端(Client),而在第一次通讯中等待连接的程序被称作服务端(Server)。一旦通讯建立,则客户端和服务器端完全一样,没有本质的区别。

接受和发出其实是可以理解为IO流

③socket与主机地址和端口号相关联,主机地址就是客户端或服务器程序所在的主机的IP地址,端口地址是指客户端或服务器程序使用的主机的通信端口。在客户端和服务器中,分别创建独立的Socket,并通过Socket的属性,将两个Socket进行连接,这样客户端和服务器通过套接字所建立连接并使用IO流进行通信。

image-20240305104756793

image-20240305112838863

Socket类概述

①Socket类实现客户端套接字(Client),套接字是两台机器间通信的端点

②Socket类构造方法:

1
public Socket(InetAddress a, int p) 创建套接字Socket并连接到指定IP地址的指定端口号

③Socket类实例方法:

1
2
3
4
5
6
7
8
9
10
11
public InetAddress getInetAddress() 返回此套接字连接到的远程 IP 地址。

public InputStream getInputStream() 返回此套接字的输入流(接收网络消息)。

public OutputStream getOutputStream() 返回此套接字的输出流(发送网络消息)。

public void shutdownInput() 禁用此套接字的输入流

public void shutdownOutput() 禁用此套接字的输出流。

public synchronized void close() 关闭此套接字(默认会关闭IO流)。

ServerSocket类概述

①ServerSocket类用于实现服务器套接字(Server服务端)。服务器套接字等待请求通过网络传入。它基于该请求执行某些操作,然后可能向请求者返回结果

②ServerSocket构造方法:

1
public ServerSocket(int port)

③ServerSocket实例方法:

1
2
3
4
5
public Socket accept() 侦听要连接到此套接字并接受它。

public InetAddress getInetAddress() 返回此服务器套接字的本地地址。

public void close() 关闭此套接字。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
ServerSocket serverSocket = null;
Socket clientSocket = null;
BufferedReader br = null;
try {
// 先启动服务器端,启动服务器端后,这个应用肯定要对应一个端口。
// 创建服务器端套接字对象
int port = 8888;
serverSocket = new ServerSocket(port);

System.out.println("服务器正在启动,请稍后....");
System.out.println("服务器启动成功,端口号" + port + ",等待客户端的请求!");

// 开始接收客户端的请求
clientSocket = serverSocket.accept();

// 后续代码怎么写一会再说!
// 服务器端接收消息,所以服务器端应该获取输入流。
br = new BufferedReader(new InputStreamReader(clientSocket.getInputStream()));

// 开始读
String s = null;
while((s = br.readLine()) != null){
System.out.println(s);
}


} catch (IOException e) {
throw new RuntimeException(e);
} finally {
if (br != null) {
try {
br.close();
} catch (IOException e) {
throw new RuntimeException(e);
}
}
if (clientSocket != null) {
try {
clientSocket.close();
} catch (IOException e) {
throw new RuntimeException(e);
}
}
// 关闭服务器端套接字
if (serverSocket != null) {
try {
serverSocket.close();
} catch (IOException e) {
throw new RuntimeException(e);
}
}
}

TCP循环发消息

1
2
3
4
5
byte[] bytes = new byte[1024];
int readCount = 0;
while((readCount = bis.read(bytes)) != -1){
bos.write(bytes, 0, readCount);
}

image-20240305111852646

TCP双向通信

①在双向通讯的案例中,客户端需要向服务端发送一张图片,服务端收到客户端发送的图片后,则需要向客户端回复收到图片的反馈。在客户端给服务端发送图片的时候,图片发送完毕必须调用shutdownOutput()方法来关闭socket输出流,否则服务端读取数据就会一直阻塞。

②服务器端实现步骤:

  1. 创建ServerSocket对象,绑定监听端口;

  2. 通过accept()方法监听客户端请求;

  3. 使用输入流接收客户端发送的图片,然后通过输出流保存图片

  4. 通过输出流返回客户端图片收到。

  5. 调用close()方法关闭资源

③客户端实现步骤:

  1. 创建socket对象,指明需要连接的服务器地址和端口号;

  2. 建立连接后,通过输出流向服务器端发送图片;

  3. 通过输入流获取服务器的响应信息;

  4. 调用close()方法关闭资源

1
2
3
4
Socket clientSocket = null;
BufferedOutputStream bos = null;
BufferedInputStream bis = null;
BufferedReader br = null;
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
clientSocket = new Socket(InetAddress.getLocalHost(), 8888);

// 发送一张图片给服务器
bos = new BufferedOutputStream(clientSocket.getOutputStream());

// 开始写图片到服务器
// 一边读一边写(读客户端本地硬盘上的图片)
bis = new BufferedInputStream(new FileInputStream("c:/dog.jpg"));

byte[] bytes = new byte[1024];
int readCount = 0;
while((readCount = bis.read(bytes)) != -1){
bos.write(bytes, 0, readCount);
}

// 刷新
bos.flush();

// 关闭输出(输出结束)
clientSocket.shutdownOutput();

// 接收服务器响应回来的消息
br = new BufferedReader(new InputStreamReader(clientSocket.getInputStream()));
String s = null;
while((s = br.readLine()) != null){
System.out.println(s);
}

基于UDP协议的编程

xxxxxxxxxx Class userClass = User.class;Constructor con = userClass.getDeclaredConstructor(Map.class);Type[] genericParameterTypes = con.getGenericParameterTypes();for(Type g :genericParameterTypes){    if(g instanceof ParameterizedType){        ParameterizedType parameterizedType = (ParameterizedType) g;        Type[] actualTypeArguments = parameterizedType.getActualTypeArguments();        for(Type a : actualTypeArguments){            System.out.println(a.getTypeName());       }   }}java

①DatagramPacket类负责把发送的数据打包(打包的数据为byte类型的数组),并且创建发送端时需指定接收端的IP地址和端口

②DatagramPacket的构造方法:

1
2
3
public DatagramPacket(byte buf[], int offset, int length) 创建接收端的数据报。

public DatagramPacket(byte buf[], int offset, int length, InetAddress address, int port) 创建发送端的数据报,并指定接收端的IP地址和端口号。

③DatagramPacket的实例方法:

1
2
3
public synchronized byte[] getData() 返回数据报中存储的数据

public synchronized int getLength() 获得发送或接收数据报中的长度

基于UDP编程的实现

①接收端实现步骤

  1. 创建DatagramSocket对象(接收端),并指定端口号;

  2. 创建DatagramPacket对象(数据报);

  3. 调用receive()方法,用于接收数据报;

  4. 调用close()方法关闭资源

1
2
3
4
5
6
7
8
9
10
11
12
13
14
DatagramSocket ds = new DatagramSocket(8888);

byte[] bytes = new byte[64 * 1024];
// 准备一个包,这个包接收发送方的信息。
DatagramPacket dp = new DatagramPacket(bytes, bytes.length);
// 程序执行到这里,停下来,等待发送方的发送。
ds.receive(dp);

// 程序执行到这里说明,已经完全将发送方发送的数据接收到了。
// 从包中取出来数据。
String msg = new String(bytes, 0, dp.getLength());
System.out.println("接收到的发送方发过来的消息:" + msg);

ds.close();

②发送端实现步骤

  1. 创建DatagramSocket对象(发送端);

  2. 创建DatagramPacket对象(数据报),并指定接收端IP地址和端口;

  3. 调用send()方法,用于发送数据报;

  4. 调用close()方法关闭资源。

1
2
3
4
5
6
7
8
9
10
DatagramSocket ds = new DatagramSocket();

// 创建包
byte[] bytes = "动力节点".getBytes();
DatagramPacket dp = new DatagramPacket(bytes, 0, bytes.length, InetAddress.getLocalHost(), 8888);

// 发送消息
ds.send(dp);

ds.close();

注解概述

什么是注解?

①注解是JDK1.5才引入的。

②注解可以标注在 类上,属性上,方法上 等。

==③注解可以做到在不改变代码逻辑的前提下在代码中嵌入补充信息。==

注解与注释

①注释:给程序员看的,编译器编译时会忽略注释。

②注解:给编译器看的,或给其它程序看的,程序根据有没有这个注解来决定不同的处理方式。

注解的重要性

①框架是如何实现的:框架 = 反射 + 注解 + 设计模式。

Java预置注解

①@Deprecated

用来标记过时的元素,在编译阶段遇到这个注解时会发出提醒警告,告诉开发者正在调用一个过时的元素比如过时的类过时的方法、过时的属性等。

forRemoval属性值表示如果是true就是已移除

②@Override

修饰实例方法,则该方法必须是个重写方法,否则就会编译失败。

③@SuppressWarnings(抑制警告的注解):在实际开发中,建议尽量不要忽略警告,而是真正的去解决警告。

1
2
3
4
5
6
7
@SuppressWarnings("rawtypes"):抑制未使用泛型的警告

@SuppressWarnings("resource"):抑制未关闭资源的警告

@SuppressWarnings("deprecation"):抑制使用了已过时资源时的警告

@SuppressWarnings("all"):抑制所有警告

④@FunctionalInterface “函数式接口”的注解

**==“函数式接口”的注解,这个是 JDK1.8 版本引入的新特性。==**:函数式接口 有且只能存在一个抽象方法

==这个注解是专门用来标注接口的==

使用@FunctionalInterface标注的接口,则该接口就有且只能存在一个抽象方法,否则就会发生编译错误。

(注意:接口中的默认方法或静态方法可以有多个。)

image-20240304223802741

自定义注解Annotation

image-20240304223916674

注解的属性是以方法这种签名实现的

自定义注解(注解属于引用数据类型)

image-20240304223840432

①使用 @interface 来定义注解。

②默认情况下注解可以出现在类上、方法上、属性上、构造方法上、方法参数上等……

③所有自定义的注解,它的父类是:java.lang.annotation.Annotation

1
2
3
4
5
6
//@Retention(value= RetentionPolicy.SOURCE) // @MyAnnotation 注解保留在源码中。
//@Retention(value= RetentionPolicy.CLASS) // @MyAnnotation 注解保留在字节码中,这是默认的行为,但不能被反射。
//@Retention(value= RetentionPolicy.RUNTIME) // @MyAnnotation 注解保留在字节码中,并且在运行时可以被反射。
@Retention(RetentionPolicy.SOURCE)
public @interface MyAnnotation {
}
1
2
3
4
5
6
7
8
9
10
@MyAnnotation
public class Test {

@MyAnnotation
int num = 100;

@MyAnnotation
public static void main(String[] args) {

}

注解也可以定义属性

①注解也可以定义属性,不过属性定义时,属性名后面必须加一个小括号。

②属性的类型只能是:

byte,short,int,long,float,double,boolean,char

String、Class、枚举类型、注解类型

以上所有类型的一维数组形式

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
/**
* 这是一个数据库信息的注解(自定义的注解)
*/
public @interface DataBaseInfo {
/**
* 注解也可以定义属性,但是属性定义时有要求,属性名后面必须添加:()
* 语法:
* 属性的类型 属性的名字();
*/
String driver() default "com.mysql.cj.jdbc.Driver"; // 使用 default 关键字来指定属性的默认值。
String url();
String user();
String password();

byte b() default 0;
short s() default 0;
int i() default 0;
long l() default 0L;
float f() default 0.0F;
double d() default 0.0;
boolean flag() default false;
char c() default '0';
Class clazz() default String.class;
Season season() default Season.SPRING;
MyAnnotation myAnnotation();

/**
* 可以是一维数组形式
* @return
*/
String[] names();

// 注解的属性的数据类型,必须是以上的几种类型,或者这几种类型的一维数组,不能是其他类型。
//Object obj();
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
// 语法规则:如果这个注解中有属性,那么使用的时候,必须给属性赋值。没有赋值则报错。
// 除非你定义注解的时候给属性指定了默认值。
// 怎么给属性赋值?语法:@DataBaseInfo(属性名=值,属性名=值,属性名=值,属性名=值,属性名=值)
@DataBaseInfo(
//driver="oracle.jdbc.driver.OracleDriver",
url="jdbc:mysql://localhost:3306/powernode",
user="root",
password="123456",
myAnnotation=@MyAnnotation,
names={"zhangsan", "lisi", "wangwu"},
flag=true,
i=100,
clazz=Integer.class,
season=Season.WINTER)
public void connDB(){

}

注解的使用

①注解在使用时必须给属性赋值,除非你使用了default关键字为属性指定了默认值。

②如果属性只有一个,并且属性名是value时,使用注解时value可以省略不写。

③如果属性是一个数组,使用注解时,数组值只有一个,数组的大括号是可以省略的。

元注解

①用来标注注解的注解叫做元注解。(也是JDK内置的注解。)

②常用的元注解:

1
2
3
4
5
6
7
8
9
@Retention:设置注解的保持性

@Target:设置注解可以出现的位置

@Documented:设置注解是否可以生成到帮助文档中

@Inherited:设置注解是否支持继承

@Repeatable:设置注解在某一个元素上是否可以重复使用(Java8的新特性。

@Retention

①Retention英文意思有保留、保持的意思,它表示注解存在阶段是保留在源代码(编译期),字节码(类加载)或者运行时(JVM中运行)。

②在@Retention注解中使用枚举RetentionPolicy来表示注解保留时期。

1
2
3
4
5
6
@Retention(RetentionPolicy.SOURCE):注解仅存在于源代码中,在字节码文件中不包含。

@Retention(RetentionPolicy.CLASS):注解在字节码文件中存在,但运行时无法获得(默认)。

@Retention(RetentionPolicy.RUNTIME):注解在字节码文件中存在,且运行时可通过反射获取。

0%