管道(父子进程)、消息队列(内核经营消息队列)、共享内存(创建一个空间)、信号(通过pid号通信)、信号量(对临界资源,共享内存做P、V控制) 。
特点:依赖于Linux内核 A B两个通信基于内核。缺陷:无法多机通信 (不适用与两台不同的电脑)
TCP和UDP对比:
TCP面向连接(如打电话要先拨号建立连接);UDP是无连接的,即发送数据之前 不需 要建立连接
TCP提供可靠的服务。也就是说,通过TCP连接传送的数据,无差错,不丢失,不重复,且按序到达;UDP尽最大努力交付,即不保证可靠交付
TCP面向字节流,实际上是TCP把数据看成一连串无结构的字节流;UDP是面向报文的UDP没有拥塞控制,因此网络出现拥塞不会使源主机的发送速率降低(对实时应用很有用,如IP电话,实时视频会议等)
每一条TCP连接只能是点到点的;UDP支持一对一,一对多,多对一和多对多的交互通信
TCP首部开销20字节;UDP的首部开销小,只有8个字节
TCP的逻辑通信信道是全双工的可靠信道,UDP则是不可靠信道
传统的进程间通信借助内核提供的IPC机制进行,但是只能限于本机通信。若要跨机通信,就必须使用网络通信,这就需要用到内核提供给用户的socket API函数库。
2.1 网络字节序
大端字节序:也叫高端字节序(网络字节序),是高端地址存放低位数据,低端地址存放高位数据
小端字节序:也叫低端字节序,是低地址存放低位数据,高地址存放高位数据。
在application.yml文件中,填入SaToken的配置信息,如下:
sa-token:
#HTTP请求头中哪个属性用来上传令牌
token-name: token
#过期时间(秒),设置为30天
timeout: 2592000
#临时有效期,设置为3天
activity-timeout: 259200
#不允许相同账号同时在线,新登陆的账号会挤掉原来登陆的账号
allow-concurrent-login: false
#在多人登陆相同账号的时候,是否使用相同的Token
is-share: false
token-style: uuid
#是否读取Cookie中的令牌
isReadCookie: false
#同端互斥
isConcurrent: false
#SaToken缓存令牌用其他的逻辑库,避免业务数据和令牌数据共用相同的Redis逻辑库
alone-redis:
database: 1
host: localhost
port: 6379
password: abc123456
timeout: 10s
lettuce:
pool:
# 连接池最大连接数
max-active: 200
# 连接池最大阻塞等待时间(使用负值表示没有限制)
max-wait: 10s
# 连接池中的最大空闲连接
max-idle: 16
# 连接池中的最小空闲连接
min-idle: 8
Java语言允许我们自己封装异常类,我们可以自定义各种异常类,比如每种业务一个异常类,或者每个模块一个异常类。我这里不想做的那么复杂,不如我们创建一个通用的异常类,用来封装与业务有关的异常信息。
在com.example.his.api.exception包中,创建HisException.java类。
package com.example.his.api.exception;
import lombok.Data;
@Data
public class HisException extends RuntimeException {
private String msg;
private int code = 500;
public HisException(Exception e) {
super(e);
this.msg = "执行异常";
}
public HisException(String msg) {
super(msg);
this.msg = msg;
}
public HisException(String msg, Throwable e) {
super(msg, e);
this.msg = msg;
}
public HisException(String msg, int code) {
super(msg);
this.msg = msg;
this.code = code;
}
public HisException(String msg, int code, Throwable e) {
super(msg, e);
this.msg = msg;
this.code = code;
}
}
SpringBoot提供了全局处理异常的技术,只要我们给某个Java类用上@RestControllerAdvice注解,这个类就能捕获SpringBoot项目中所有的异常,然后统一处理(精简异常信息)再返回给前端项目。
在com.example.his.api.config包中,创建ExceptionAdvice.java类。
package com.example.his.api.config;
import cn.dev33.satoken.exception.NotLoginException;
import cn.felord.payment.PayException;
import cn.hutool.json.JSONObject;
import com.example.his.api.exception.HisException;
import lombok.extern.slf4j.Slf4j;
import org.springframework.validation.BindException;
import org.springframework.http.HttpStatus;
import org.springframework.http.converter.HttpMessageNotReadableException;
import org.springframework.web.HttpRequestMethodNotSupportedException;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.ResponseStatus;
import org.springframework.web.bind.annotation.RestControllerAdvice;
import org.springframework.web.multipart.support.MissingServletRequestPartException;
@Slf4j
@RestControllerAdvice
public class ExceptionAdvice {
/*
* 捕获异常,并且返回500状态码
*/
@ResponseBody
@ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)
@ExceptionHandler(Exception.class)
public String exceptionHandler(Exception e) {
JSONObject json = new JSONObject();
if (e instanceof HttpMessageNotReadableException) {
HttpMessageNotReadableException exception = (HttpMessageNotReadableException) e;
log.error("error", exception);
json.set("error", "请求未提交数据或者数据有误");
}
else if (e instanceof MissingServletRequestPartException) {
MissingServletRequestPartException exception = (MissingServletRequestPartException) e;
log.error("error", exception);
json.set("error", "请求提交数据错误");
}
else if (e instanceof HttpRequestMethodNotSupportedException) {
HttpRequestMethodNotSupportedException exception = (HttpRequestMethodNotSupportedException) e;
log.error("error", exception);
json.set("error", "HTTP请求方法类型错误");
}
//Web方法参数数据类型转换异常,比如String[]数组类型的参数,你上传的数据却是String类型
else if (e instanceof BindException) {
BindException exception = (BindException) e;
String defaultMessage = exception.getFieldError().getDefaultMessage();
log.error(defaultMessage, exception);
json.set("error", defaultMessage);
}
//没有通过后端验证产生的异常
else if (e instanceof MethodArgumentNotValidException) {
MethodArgumentNotValidException exception = (MethodArgumentNotValidException) e;
json.set("error", exception.getBindingResult().getFieldError().getDefaultMessage());
}
//处理业务异常
else if (e instanceof HisException) {
log.error("执行异常", e);
HisException exception = (HisException) e;
json.set("error", exception.getMsg());
}
//微信支付异常
else if (e instanceof PayException) {
PayException exception = (PayException) e;
log.error("微信支付异常", exception);
json.set("error", "微信支付异常");
}
//处理其余的异常
else {
log.error("执行异常", e);
json.set("error", "执行异常");
}
return json.toString();
}
/*
* 捕获异常,并且返回401状态码
*/
@ResponseBody
@ResponseStatus(HttpStatus.UNAUTHORIZED)
@ExceptionHandler(NotLoginException.class)
public String unLoginHandler(Exception e) {
JSONObject json = new JSONObject();
json.set("error", e.getMessage());
return json.toString();
}
}
因为Controller类用上@RestController注解之后,Web方法返回的对象会被自动转换成JSON对象,所以我们只需要声明一个封装类,让所有Web方法返回这个封装类的对象即可。除了公共属性之外,不同的Web方法要返回的业务数据也不尽相同,所以选择动态的结构才是最佳的方案,恰好HashMap允许我们随便添加数据,那就选择HashMap作为父类吧。在com.example.his.api.common包中,创建R.java类。
package com.example.his.api.common;
import org.apache.http.HttpStatus;
import java.util.HashMap;
import java.util.Map;
public class R extends HashMap<String, Object> {
public R() {
//默认创建的R对象中包含了公共的属性
put("code", HttpStatus.SC_OK);
put("msg", "success");
}
/*
* 覆盖继承的put函数,添加Key-Value数据
*/
public R put(String key, Object value) {
super.put(key, value);
//把自己返回,用于链式调用
return this;
}
public static R ok() {
return new R();
}
public static R ok(String msg) {
R r = new R();
r.put("msg", msg);
return r;
}
public static R ok(Map<String, Object> map) {
R r = new R();
r.putAll(map);
return r;
}
public static R error(int code, String msg) {
R r = new R();
r.put("code", code);
r.put("msg", msg);
return r;
}
public static R error(String msg) {
return error(HttpStatus.SC_INTERNAL_SERVER_ERROR, msg);
}
public static R error() {
return error(HttpStatus.SC_INTERNAL_SERVER_ERROR, "未知异常,请联系管理员");
}
}