java开发,常见概念

Java


人人开源代码生成器:https://gitee.com/renrenio/renren-generator.git
所有idea快捷键: 博客csdn @ 绿茵场上的程序猿
spring平台各组件版本对应:https://spring.p2hp.com/projects/spring-cloud.html
aliyun的mvn仓库:https://developer.aliyun.com/mvn/search
spring security用法:Spring Security使用详解(基本用法 ) - 邓维-java - 博客园
spring security视频:https://www.bilibili.com/video/BV1kj41167rK?t=518.7&p=4

java开发框架需要实现这些功能:面向对象和自动GC(java语言特性)、面向切面、控制反转(ioc和di)、包管理工具、orm、mvc、web、事务、微服务。
spring的主要模块:spring本身的基础特性、springboot自动配置、springmvc。

# 面向对象和自动GC
java语言特性实现
# 面向切面
spring框架实现。
# 控制反转(ioc和di)
spring框架实现。
# 包管理工具
maven
# orm
mybatisplus实体映射模型
# mvc

# web
spring web框架,还提供restful api组件、rpc组件,ribbon工具可以提供基于负载均衡算法的rest调用,cloud提供openfeign远程调用
# 事务。
spring框架的transaction组件

java语法

基本数据类型:https://www.php.cn/faq/500617.html

命名规范、基本数据类型、常用数据结构封装类、代码语法(类定义变量定义函数定义控制结构语法注解语法异常语法并发语法)、常用基础库(os、文件、path、http、并发、异常)、面向对象支持、aop支持、ioc和di支持、jdk版本。

# 命名规范
包名。全部小写不要下划线。
类名。驼峰命名法不要下划线首字母大写,抽象类以Abstract或者Base为前缀,接口实现类以Impl为后缀,异常类以Exception为后缀,测试类以Test为后缀。
方法变量。驼峰命名法不用下划线首字母小写,有返回值加get前缀,设置方法加动词前缀修饰如set、insert、update、delete,查询方法加select、find、query前缀,带有条件的方法用By或者With连接,判断方法加is前缀,测试方法加test前缀。
常量。全部大写用下划线分割。
枚举类。类名遵循类名命名,值遵循常量命名法。
泛型。E表示元素element通常用在集合中,T表示类型type通常指类,K/V表示键值对key/value通常成对用于Map中,N表示数值类型Number,?表示不确定的java类型,X表示异常,U/S表示任意类型。
# 基本数据类型
java中有7种基本数据类型byte,short,int,long,float,double,boolean,char
byte。8位,-128~127。
short。16位,-32768~32767。
int。32位,-2.1e9~2.1e9。
long。64位,-9.2e18~9.2e18。
float。32位,3.4e-45~1.4e38,直接赋值必须加f/F。
double。64位,4.9e-324~1.8e308,直接赋值可加可不加d/D,因为小数常量默认类型是double。
boolean。1位,true/false。
char。16位存储unicode码,用单引号赋值。
基本类型的位数和取值范围可以使用包装类.SIZE/.MIN_VALUE/.MAX_VALUE获取,其中float和double的.MIN_VALUE不是最小的负数而是最小的正小数,即0+-Float.MIN_VALUE之间的数float无法表示因为超出了float的精度范围。
# 常用数据结构封装类
list, map, set, linklist, hashmap, hashset, 
# 代码语法
类定义。
变量定义。
函数定义。
控制结构语法。
注解语法。
异常语法。
并发语法。

# 常用基础库
os。
文件。
path。
http。
并发。
异常。

# 面向对象支持

# aop支持

# ioc和di支持

# jdk版本
jdk5.0(1.5)开始实现了自动装包和拆包

springboot经验

springboot的使用:http://t.csdnimg.cn/gLKw4
springboot面试题:https://www.bilibili.com/video/BV1Fh4y1D7Aq?t=7.9&p=4

概念。springboot是spring的一个模块,旨在简化spring应用程序的创建和部署,提供了一些额外特性来简化配置和开发过程。

使用方法。举一个例子,比如说在项目中使用了MySQL数据库,那么就引入MySQL依赖包,然后在application配置文件中配置数据源信息,springboot会根据项目依赖中的MySQL依赖自动读取配置文件中的数据源信息,然后将配置信息应用到对应的数据容器中,springboot内嵌了web服务器,因此springboot打包之后可以直接通过jar -jar命令运行。springboot的使用方式就引入springboot依赖,然后在启动类中设置@sprongbootapplication注解,在配置yaml文件中配置数据连接字符串,使用spring的依赖注入功能,在业务类和控制器中使用@service和@restcontroller可以完成自动注入,引入mybatis依赖,使用@mappingscan注解映射mapper的位置,之后完成相关的业务代码和控制器就可以启动应用了。

问题1-在项目中是怎么使用springboot的?

首先是引入一个spring-boot-starter依赖作为父依赖,然后根据项目场景引入springweb或者springmvc之类的依赖和mysql、mybatis等依赖,在properties配置文件中配置数据源和端口等信息,为启动类添加@springbootApplication注解,之后编写业务代码就可以启动应用了。

问题1-springboot的启动原理。

7步。
运行main方法。
运行run方法。在run方法中会读取配置信息、创建上下文、初始化上下文、加载ioc容器。在这个过程中调用很多监听器用于扩展。

问题2-springboot自动配置的原理,讲一下常用的注解和类?

6步。
通过@SpringBootApplication引入@SpringBootConfiguration和@EnableAutoConfiguration
通过@EnableAutoConfiguration引入@Import
通过@Import导入DeferredImportSelector组件
DeferredImportSelector会读取所有/META-INF/spring.factories文件
过滤出所有AutoConfigurationClass的类
通过@ConditionOnXXX排除无效的自动配置类。

事务

spring transaction。事务的使用就是使用@transactional注解。

# 实现方式
4种。编程式,transactionProxyFactoryBean的声明式事务,AspectJ的XML声明式事务,基于注解的声明式事务。
# 功能
一系列动作要么全完成,要么全不完成。
https://blog.csdn.net/2301_78145678/article/details/130753716

mysql经验


问题1-mysql的索引

ssm经验

目标:使用ssm开发一个后台管理系统。

涉及的技术:ssm、thymeleaf、mysql

主要内容:

ssm是指使用spring、springmvc、mybatis开发的项目。

1)spring是一个开源的应用程序框架,提供了一种全面的编程和配置模型,spring的核心特性包括依赖注入、面向切面、控制反转等。spring支持各种开发层次,包括web应用开发、数据访问、消息传递等,它提供了一系列的模块,如spring mvc、spring data、spring security等。spring框架提供了一个容器ApplicationContext,用于管理和组织应用程序中的对象,主要有5个方面的作用:bean的管理、依赖注入、AOP支持、国际化支持、事件机制。

2)springmvc是spring框架中的一个模块,用于构建web应用程序。springmvc提供了一种分离关注点的方式,使得开发人员可以专注于业务逻辑/模型、用户界面/视图、处理用户请求/控制器 3个部分。

面向切面

spring框架实现。

控制反转(ioc和di)

spring框架实现。

orm框架

# mybatisplus
mybatisplus是操作mysql的orm框架,使用jdbc作为mysql数据库驱动,支持mysql sqlserver oracle sqlite mariadb db2 h2 hsql postgresql 
达梦数据库 虚谷数据库 人大金仓数据库等这些数据库软件。
# RedisTemplate
访问redis的组件,jdk11可以使用redisom官方组件,jdk8使用redistemplate。
# rabbitmq
session消息中间件,其他消息中间件还有kafka

pojo

pojo类英文全称是plain ordinary java object,中文叫做普通java对象,pojo包括实体类entity、视图对象vo、业务传输对象dto等一众java对象。

高并发


高并发商城项目需要使用spring提供基本的ioc和aop功能,需要使用springboot提供默认配置,简化开发,需要使用springcloud提供网关和负载均衡,需要使用elastic search提供对商品的全文检索,需要使用redis对商品信息进行缓存,对用户session进行缓存,需要使用rabbitmq进行流量消峰。
基础服务需要使用mysql进行数据存储。
明天讲一下MySQL的分库分表。

高并发主要是使用3个工具:缓存、异步、队列。
缓存就是使用redis作为缓存数据库,掌握redis数据库的使用。异步就是使用消息中间件进行异步解耦,进行流量的缓存。队列就是让高并发的请求排队逐一处理。主要工具:redis、kafka和rabbitmq。

java小厂技术


ssm+mysql已经可以解决大部分小厂的问题了,就我实习过的一家帮助医院录入老年人就诊信息的小公司,就是使用ssm+mysql做一个简单的信息管理系统,只要学过软件的人基本都能做。下面说一下需要学习的技术。

面试提问:spring提供基本的ioc和aop功能,说一下实现原理。

springcloud

# springcloud
提供微服务和云原生功能组件.
# springcloud gateway
网关
# nacos
注册发现配置中心

常用命令

# 运行
java -jar ./target/spring-petclinic-3.1.0-SNAPSHOT.jar

版本管理github经常连不上使用码云配置.gitignore排除不进行版本控制的文件。

**/mvnw
**/mvnw.cmd
**/.mvn
**/target/
.idea
**/.gitignore

组件版本

版本适配:jdk1.8, springboot-2.2.6.RELEASE, springcloud-Hoxton.SR1, springcloudalibaba-2.2.6.RELEASE, mybatis-plus-3.3.0, mysqlconnectorjava-8.0.33, Spring Cloud Gateway-2.2.1.RELEASE, nacos2.2.6

组件依赖版本
JDK1.8
Spring包含于spring-boot-starter-parent
SpringBootspring-boot-starter-parent1.5.10.RELEASE
SpringWebspring-boot-starter-web依赖于spring-boot-starter-parent
SpringMVC包含于spring-boot-starter-web
Mybatismybatis-spring2.0.6
Mybatis-Plusmybatis-plus-boot-starter3.0-RELEASE
Lombok1.16.20
Thymeleafspring-boot-starter-thymeleaf依赖于spring-boot-starter-parent

快捷键

# 快捷键
自动缩进行:ctrl+alt+l
跳转到implementation类:ctrl+alt+B
跳转到方法实现处:ctrl+B
根据类名查找类:ctrl+N
查看接口的所有实现类:ctrl+H
重命名:shift+f6
# 服务启动参数设置
设置服务启动端口:Program arguments :--server.port=9011

代码生成器

代码生成器有人人开源和MybatisPlus-generator,人人开源的用法是通过git下载源码修改application.yml更新MySQL账号和密码数据库名称修改generator.properties更新包名表前缀修改模板运行RenrenApplication.java启动项目访问http://localhost即可。

generator.properties

mainPath=com.zhou
#包名
package=com.zhou
moduleName=seckill
#作者
author=zhoujk
#Email
email=zhoujkmail@163.com
#表前缀
tablePrefix=

controller

// 删除 @RequiresPermissions一共有4个
import org.springframework.beans.factory.annotation.Autowired;
@RequiresPermissions("${moduleName}:${pathName}:list")
// 修改
import ${package}.${moduleName}.utils.PageUtils;
import ${package}.${moduleName}.utils.R;
@RequestMapping("${pathName}")


service

// 修改
import ${package}.${moduleName}.utils.PageUtils;
// 注释掉
    // PageUtils queryPage(Map<String, Object> params);

impl

// 修改
import ${package}.${moduleName}.utils.PageUtils;
import ${package}.${moduleName}.utils.Query;
// 注释掉
    /**
     @Override
     public PageUtils queryPage(Map<String, Object> params) {
         IPage<${className}Entity> page = this.page(
                 new Query<${className}Entity>().getPage(params),
                 new QueryWrapper<${className}Entity>()
         );
         return new PageUtils(page);
     }
     */

Mybatis-Plus

  1. 添加依赖

​ MyBatis-Plus依赖、MySQL驱动、httpcomponents依赖、servlet依赖

    <!--业务需求-->
        <!--集成spring-web-mvc-->

        <dependency>
            <groupId>org.apache.httpcomponents</groupId>
            <artifactId>httpcore</artifactId>
            <version>4.4.15</version>
            <scope>compile</scope>
        </dependency>
        <dependency>
            <groupId>org.apache.httpcomponents.core5</groupId>
            <artifactId>httpcore5</artifactId>
            <version>5.1.4</version>
        </dependency>
        <dependency>
            <groupId>javax.servlet</groupId>
            <artifactId>javax.servlet-api</artifactId>
            <version>3.1.0</version>
            <scope>provided</scope>
        </dependency>
        <!--生成业务代码 MyBatisPlus-->
        <dependency>
            <groupId>com.baomidou</groupId>
            <artifactId>mybatis-plus-boot-starter</artifactId>
            <version>3.5.1</version>
        </dependency>
        <!--MySQL-->
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>8.0.30</version>
        </dependency>
        <!-- 集成mybatis -->
        <dependency>
            <groupId>org.mybatis</groupId>
            <artifactId>mybatis-spring</artifactId>
            <version>2.0.6</version>
            <scope>compile</scope>
        </dependency>
  1. 注册mapper

​ 为XxxApplication.java添加注解

@MapperScan(“com.zhou.seckill.dao”)
  1. 配置application.yml
## 数据源、映射文件位置
spring:
 datasource:
  username: root
  password: zhoujkAAAAA
  url: jdbc:mysql://192.168.137.2:3306/seckill
  driver-class-name: com.mysql.cj.jdbc.Driver

mybatis-plus:
 mapper-locations: classpath:/mapper/**/*.xml
 global-config:
  db-config:
   id-type: auto

## 应用服务 WEB 访问端口
server:
 port: 8082

thymeleaf

1)添加依赖

        <!-- 整合thymeleaf,前端引擎 -->
		<dependency>
           <groupId>org.springframework.boot</groupId>
           <artifactId>spring-boot-starter-thymeleaf</artifactId>
        </dependency>
        <!-- thymeleaf热部署,修改html之后立即生效 -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-devtools</artifactId>
            <optional>true</optional>
        </dependency>
## 关闭 thymeleaf 缓存,实现热部署
spring.thymeleaf.cache=false

2)编写html页面

所有html页面默认放在resources/template下面,默认访问index.html页面。

<!DOCTYPE HTML>
<html xmlns:th="http://www.thymeleaf.org">
<head>
    <title>Index Page</title>
    <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
</head>
<body>
    <p th:text="${message}">Welcome to BeiJing!</p>
</body>
</html>

3)编写Controller

// 只有@Controller的时候返回“login”才会生效,使用@RestController需要返回new ModelAndView("login")才会路由到页面。
@Controller
@RequestMapping("page")
public class PageController {
    /**
     * 进入登录页
     */
    @RequestMapping("/login")
    public String loginPage(){
        return "login";
    }
}

Cookie\Session

演示:登录模块

1)写接口

@RequestMapping("login")
public Result<User> doLogin(HttpServletResponse response, HttpSession session, 
                            @Valid LoginParam loginParam){
    Result<User> login = userService.login(loginParam);
    return login;
}

2)生成 Cookie 和Session

生成Cookie ,写入到HttpServletResponse中。

    private final static String COOKIE_DOMAIN = "localhost";
    private final static String COOKIE_NAME = "seckill_login_token";
    /**
     * token = httpSession.getId();
     */
	public static void writeLoginToken(HttpServletResponse response, String token){
        Cookie cookie = new Cookie(COOKIE_NAME,token);
        cookie.setDomain(COOKIE_DOMAIN);
        cookie.setPath("/");//代表设置在根目录
        cookie.setHttpOnly(true);
        //单位是秒。
        //如果这个MaxAge不设置的话,cookie就不会写入硬盘,而是写在内存。只在当前页面有效。
        cookie.setMaxAge(60 * 60 * 24 * 365);//如果是-1,代表永久
        log.info("write cookieName:{},cookieValue:{}",cookie.getName(),cookie.getValue());
        response.addCookie(cookie);
    }

生成 Session ,保存到 Redis 中。

redisService.set(UserKey.getByName, httpSession.getId(), login.getData(),		
                 Const.RedisCacheExtime.REDIS_SESSION_EXTIME);

3)读取 Cookie 和 Session

读取Cookie

    private final static String COOKIE_DOMAIN = "localhost";
    private final static String COOKIE_NAME = "seckill_login_token";
	public static String readLoginToken(HttpServletRequest request){
        Cookie[] cks = request.getCookies();
        if(cks != null){
            for(Cookie ck : cks){
                log.info("read cookieName:{},cookieValue:{}",ck.getName(),ck.getValue());
                if(StringUtils.equals(ck.getName(),COOKIE_NAME)){
                    log.info("return cookieName:{},cookieValue:{}",ck.getName(),ck.getValue());
                    return ck.getValue();
                }
            }
        }
        return null;
    }

读取Session

    User user = redisService.get(UserKey.getByName, loginToken, User.class);

3)删除 Cookie 和 Session

删除Cookie

	public static void delLoginToken(HttpServletRequest request, HttpServletResponse response){
        Cookie[] cookies = request.getCookies();
        if(cookies != null){
            for(Cookie cookie : cookies){
                if(StringUtils.equals(cookie.getName(),COOKIE_NAME)){
                    cookie.setDomain(COOKIE_DOMAIN);
                    cookie.setPath("/");
                    cookie.setMaxAge(0);//设置成0,代表删除此cookie。
                   // log.info("del cookieName:{},cookieValue:{}",ck.getName(),ck.getValue());
                    response.addCookie(cookie);
                    return;
                }
            }
        }
    }

删除Session

        redisService.del(UserKey.getByName , token);

Transaction

在需要执行事务的方法上方添加@Transactional注解

 @Transactional
 public OrderInfo insert(User user, GoodsBo goods) {
        //秒杀商品库存减一
    	//插入秒杀表
 }

Lombok

直接添加Lombok依赖即可,可用于在entity类添加@Data注解。

Logging

配置

logging:
  level:
    com.netflix: WARN
    org.springframework.web: WARN
    com.zhou: INFO


OSS


  1. 视频教程 bilibili @ 徐庶老师
  2. el-upload: https://element.eleme.cn/#/zh-CN/component/upload
  3. 上传参数: 链接
  4. axios使用:https://blog.csdn.net/qq_30631063/article/details/107099336

使用谷粒商城写好的Singleupload.Vue和MultiUpload.Vue两个组件之后报错:The OSS Access Key Id you provided does not exist in our records。原因:封装上传参数的时候参数名称没有写对,改过来就好了。

dataObj: {
	OSSAccessKeyId: '',
	policy: '',
	Signature: '',
	key: '',
	host: '',
	dir: '',
	uuid: ""
},

在阿里云OSS对象存储控制台创建bucket,并设置为 公共读 和 允许跨域。

在阿里云RAM控制台创建子用户,保存用户ID和KEY(只在创建时显示,之后无法再查看):

access-key: LTAI5tMLTWzrybw6qw6RwhYd
secret-key: wfgKv6jkJXQbyyZcp75NWE2wgPMPHE

为该子用户添加权限:

{AliyunOSSFullAccess 管理对象存储服务(OSS)权限(已添加)}(添加这1个就可以了)

third-party的pom添加依赖:aliyun-oss-spring-boot-starter

添加bootstrap.properties文件:

spring.application.name=zhoumall-third-party
spring.cloud.nacos.server-addr=127.0.0.1:8848
spring.cloud.nacos.config.namespace=bf88dd25-311b-42b4-9729-9facaa8cad40
spring.cloud.nacos.config.extension-configs[0].data-id=oss.yml
spring.cloud.nacos.config.extension-configs[0].group=DEFAULT_GROUP
spring.cloud.nacos.config.extension-configs[0].refresh=true

添加配置项oss.xml:

spring:
  cloud:
    alicloud:
      access-key: LTAI5tDEftneVL9Gua3XHMd5
      secret-key: ITlo1G4uThQCbg8m2aZLXHfz4AykZo
      oss:
        endpoint: oss-cn-qingdao.aliyuncs.com

枚举请求状态

constant文件夹:创建一个CodeMsg类枚举常用状态码和状态信息

public class CodeMsg {
	private int code;
	private String msg;	
	......	
	public static CodeMsg SUCCESS = new CodeMsg(0, "success");
	public static CodeMsg SERVER_ERROR = new CodeMsg(500100, "服务端异常");
	......
}

全局统一返回

utils文件夹:创建一个Result类统一所有api返回的数据格式。

public class Result<T> {
	private int code;
	private String msg;
	private T data;
    ......
}

MD5密文存储

前后端都要实现MD5加密,后端原理不懂,前端代码不懂。

1)添加MD5依赖

 		<!-- MD5加密 -->
        <dependency>
            <groupId>commons-codec</groupId>
            <artifactId>commons-codec</artifactId>
        </dependency>
        <!-- 使用StringUtils类需要添加依赖 -->
        <dependency>
        	<groupId>org.apache.commons</groupId>
        	<artifactId>commons-lang3</artifactId>
        	<version>3.6</version>
        </dependency>

2)实现MD5加密

创建一个工具类MD5Util

import org.apache.commons.codec.digest.DigestUtils;
public class MD5Util {
    // 加密算法
	public static String md5(String src) {
		return DigestUtils.md5Hex(src);
	}
	// 盐
	private static final String salt = "9d5b364d";
	// 明文+盐➡加密➡密文
	public static String inputPassToFormPass(String inputPass) {
		String str = ""+salt.charAt(0)+salt.charAt(2) + inputPass +salt.charAt(5) + salt.charAt(4);
		return md5(str);
	}
	// 密文+盐➡加密➡数据库密文
	public static String formPassToDBPass(String formPass, String salt) {
		String str = ""+salt.charAt(0)+salt.charAt(2) + formPass +salt.charAt(5) + salt.charAt(4);
		return md5(str);
	}
	// 明文+盐➡加密➡密文,密文+盐➡加密➡数据库密文
	public static String inputPassToDbPass(String inputPass, String saltDB) {
		String formPass = inputPassToFormPass(inputPass);
		String dbPass = formPassToDBPass(formPass, saltDB);
		return dbPass;
	}
	// test
	public static void main(String[] args) {
		System.out.println(inputPassToDbPass("12345678", "9d5b364d"));  // cd235d8b395725d4c3352e9689f346b6
	} 
}

3)用法

		String dbPwd= user.getPassword();
		String dbSalt = user.getSalt();
		String calcPass = MD5Util.formPassToDBPass(loginParam.getPassword(), dbSalt);

实体类别划分

实体类别备注
entity数据库实体类
param接口参数封装类
bo业务中间数据实体类,封装了业务中间状态的数据格式,可以包含业务方法
constant各种枚举常量

参数校验

见文档JSR303.md

使用参数校验

1)引入依赖

参考 cnblog https://www.cnblogs.com/yjiu/p/15780130.html

<!--参数校验-->
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-validation</artifactId>
</dependency>

1)校验规则注解

​ 为实体类添加注解

@NotBlank(message = "name不能为空")
@NotEmpty
@URL(message = "logo必须是一个合法的url")
@NotEmpty // 作用于列表数组等
@Pattern(regexp = "^[a-zA-Z]$", message = "检索首字母必须是一个字母")
@NotNull // 作用于对象上
@Min(value = 0, message = "排序必须大于等于0")

2)校验标识注解

​ 为参数添加注解@Valid

@RequestMapping("/login")
public String login(HttpRequest request, HttpResponse response, @Valid LoginParam loginParam){
    return "login";
}

4)校验配置

​ 配置文件中添加配置,自动返回错误信息

include-binding-errors: always

自定义参数校验

1)定义校验规则注解

@Target({ METHOD, FIELD, ANNOTATION_TYPE, CONSTRUCTOR, PARAMETER })
@Retention(RUNTIME)
@Documented
@Constraint(validatedBy = {IsMobileValidator.class})
public @interface  IsMobile {
	boolean required() default true;
	String message() default "手机号码格式错误";
	Class<?>[] groups() default { };
	Class<? extends Payload>[] payload() default { };
}

2)定义校验器

public class IsMobileValidator implements ConstraintValidator<IsMobile, String> {
	private boolean required = false;
	public void initialize(IsMobile constraintAnnotation) {
		required = constraintAnnotation.required();
	}
	public boolean isValid(String value, ConstraintValidatorContext context) {
		if(required) {
			return ValidatorUtil.isMobile(value);
		}else {
			if(StringUtils.isEmpty(value)) {
				return true;
			}else {
				return ValidatorUtil.isMobile(value);
			}
		}
	}
}

3)实现校验逻辑

定义校验工具类

public class ValidatorUtil {
	private static final Pattern mobile_pattern = Pattern.compile("1\\d{10}");
	public static boolean isMobile(String src) {
		if(StringUtils.isEmpty(src)) {
			return false;
		}
		Matcher m = mobile_pattern.matcher(src);
		return m.matches();
	}
}

统一异常处理

编码步骤:

  1. zhoumall-product中创建异常目录:com.zhou.mall.product.exception
  2. 创建异常处理文件:ZhoumallExceptionControllerAdvice.java
  3. 编写异常处理逻辑:针对不同的异常类型编写不同的异常处理方法
// 处理数据校验异常
@ExceptionHandler(value = MethodArgumentNotValidException.class)
public R handleValidException(MethodArgumentNotValidException e) {
    log.error("数据校验出现问题:{},异常类型:{}", e.getMessage(), e.getClass());
    BindingResult bindingResult = e.getBindingResult();
    Map<String, String> map = new HashMap<>();
    bindingResult.getFieldErrors().forEach((fieldError -> {
        map.put(fieldError.getField(), fieldError.getDefaultMessage());
    }));
    return R.error(400, "数据校验异常").put("data", map);
}
// 处理其他异常
@ExceptionHandler
public R handleException(Exception e){
    return R.error();
}

定义错误状态码和错误信息

  1. zhoumall-common中创建异常处理目录:com.zhou.common.exception
  2. 编写枚举类BizCodeEnume
package com.zhou.common.exception;

/**
 * 错误码和错误信息校验类:
 * 1. 错误码定义规则为5位数字
 * 2. 前两位表示业务场景,最后三位表示错误码。例如:10001。10:通用,001系统未知异常
 * 3. 维护错误码后需要维护错误描述,将他们定义为枚举类型
 *
 * 错误码列表
 * 10:通用
 *      001:参数格式校验
 * 11:商品
 * 12:订单
 * 13:购物车
 * 14:物流
 */
public enum BizCodeEnume {
    UNKNOW_EXCEPTION(10000,"系统未知异常"),
    VALID_EXCEPTION(10001, "参数校验失败");
    private int code;
    private String message;
    BizCodeEnume(int code, String message){
        this.code = code;
        this.message = message;
    }

    public int getCode() {
        return code;
    }

    public String getMessage() {
        return message;
    }
}
  1. 返回的状态码和错误消息直接从枚举类中获取
return R.error(BizCodeEnume.VALID_EXCEPTION.getCode(), BizCodeEnume.VALID_EXCEPTION.getMessage()).put("data", map);

分组校验

  1. 在zhoumall-common中添加分组校验目录和2个分组校验组别接口

  1. 添加分组校验组别groups={AddGroup.class, UpdateGroup.class}
@NotEmpty(message = "logo地址不能为空", groups = {AddGroup.class})
@URL(message = "logo必须是一个合法的url", groups = {AddGroup.class, UpdateGroup.class})
private String logo;
  1. Controller中方法参数换成@Validated({AddGroup.class})
public R save(@Validated({AddGroup.class}) @RequestBody BrandEntity brand /*, BindingResult result*/)

注意:使用@Validate注解之后,bean属性中注解没有添加groups的校验默认不生效,这点和@Valid注解不同。

编码到P69 00:00 自定义校验规则

自定义校验注解

1)定义校验规则注解

​ 编写一个自定义的校验注解&自定义该注解的配置信息

@Documented
@Constraint(validatedBy = {ListValueConstraintValidator.class})
@Target({ElementType.METHOD, ElementType.FIELD, ElementType.ANNOTATION_TYPE, ElementType.CONSTRUCTOR, ElementType.PARAMETER, ElementType.TYPE_USE})
@Retention(RetentionPolicy.RUNTIME)
public @interface ListValue {
   String message() default "{com.zhou.common.valid.ListValue.message}";
   Class<?>[] groups() default {};
   Class<? extends Payload>[] payload() default {};
   int[] vals() default {};
}

2)配置注解信息

​ ValidationMessages.properties

com.zhou.common.valid.ListValue.message=必须提交指定的值

3)定义的校验器

public class ListValueConstraintValidator implements ConstraintValidator<ListValue, Integer> {
  private Set<Integer> set = new HashSet<>();
  // 初始化方法
  @Override
  public void initialize(ListValue constraintAnnotation) {
    ConstraintValidator.super.initialize(constraintAnnotation);
    int[] vals = constraintAnnotation.vals();
    for (int val : vals) {
      set.add(val);
    }
  }

  /**
   * 判断是否校验成功
  	* @param integer 需要校验的值
   */
   @Override
   public boolean isValid(Integer integer, ConstraintValidatorContext constraintValidatorContext) {
        return set.contains(integer);
   }
}
  1. 关联自定义的校验注解和自定义的校验器
@Constraint(validatedBy = {ListValueConstraintValidator.class})

MySQL


数据源配置

## 数据源
spring:
  datasource:
    username: root
    password: zjk123456
    url: jdbc:mysql://192.168.137.32:3306/gulimall_sms
    driver-class-name: com.mysql.cj.jdbc.Driver

Redis


redis缓存的使用

1)添加依赖

        <!--redis-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-redis</artifactId>
        </dependency>
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>fastjson</artifactId>
            <version>1.2.31</version>
        </dependency>

2)定义配置类

配置项实体类 RedisConfig.java

@Setter
@Getter
@Component
@ConfigurationProperties(prefix="redis")
public class RedisConfig {
	private String host;
	private int port;
	private int timeout;//秒
	private String password;
	private int poolMaxTotal;
	private int poolMaxIdle;
	private int poolMaxWait;//秒
}

增加配置项数据 application.yaml

redis:
  host: 192.168.137.2
  password: 123456
  poolMaxIdle: 500
  poolMaxTotal: 1000
  poolMaxWait: 500
  port: 6379
  timeout: 10

3)创建redis客户端

操作Redis的客户端有2种可选:JedisRedisTemplate,这里选择的是Jedis

RedisPoolFactory.java

@Service
public class RedisPoolFactory {
	@Autowired
	RedisConfig redisConfig;
	@Bean
	public  JedisPool JedisPoolFactory() {
		JedisPoolConfig poolConfig = new JedisPoolConfig();
		poolConfig.setMaxIdle(redisConfig.getPoolMaxIdle());
		poolConfig.setMaxTotal(redisConfig.getPoolMaxTotal());
		poolConfig.setMaxWaitMillis(redisConfig.getPoolMaxWait() * 1000);
		JedisPool jp = new JedisPool(poolConfig, redisConfig.getHost(), redisConfig.getPort(),
				redisConfig.getTimeout()*1000, redisConfig.getPassword(), 0);
		return jp;
	}
}

4)创建redis服务类

RedisService.java

@Service
public class RedisService {
	@Autowired
	JedisPool jedisPool;
	/**
	 * 增(存入对象)
	 * */
	public <T> boolean set(KeyPrefix prefix, String key,  T value ,int exTime) {
		 Jedis jedis = null;
		 try {
			 jedis =  jedisPool.getResource();
			 String str = beanToString(value);
			 if(str == null || str.length() <= 0) {
				 return false;
			 }
			//生成真正的key
			 String realKey  = prefix.getPrefix() + key;
			 if(exTime == 0) {
			 	 //直接保存
				 jedis.set(realKey, str);
			 }else {
			 	 //设置过期时间
				 jedis.setex(realKey, exTime, str);
			 }
			 return true;
		 }finally {
			  returnToPool(jedis);
		 }
	}
	/**
	 * 删
	 */
	public  Long del(KeyPrefix prefix,String key){
		Jedis jedis = null;
		Long result = null;
		try {
			jedis =  jedisPool.getResource();
			result = jedis.del(prefix.getPrefix()+key);
			return result;
		} finally {
			returnToPool(jedis);
		}
	}
	/**
	 * 改(修改过期时间)
	 */
	public  Long expire(KeyPrefix prefix,String key,int exTime){
		Jedis jedis = null;
		Long result = null;
		try {
			jedis =  jedisPool.getResource();
			result = jedis.expire(prefix.getPrefix()+key,exTime);
			return result;
		} finally {
			returnToPool(jedis);
		}
	}
	/**
	 * 改(将值自增1,不存在就先置0)
	 * */
	public <T> Long incr(KeyPrefix prefix, String key) {
		 Jedis jedis = null;
		 try {
			 jedis =  jedisPool.getResource();
			//生成真正的key
			 String realKey  = prefix.getPrefix() + key;
			return  jedis.incr(realKey);
		 }finally {
			  returnToPool(jedis);
		 }
	}
	/**
	 * 改(将值自减1,如果值不存在就先置0再自减1)
	 * */
	public <T> Long decr(KeyPrefix prefix, String key) {
		 Jedis jedis = null;
		 try {
			 jedis =  jedisPool.getResource();
			//生成真正的key
			 String realKey  = prefix.getPrefix() + key;
			return  jedis.decr(realKey);
		 }finally {
			  returnToPool(jedis);
		 }
	}
	/**
	 * 查(返回对象)
	 * */
	public <T> T get(KeyPrefix prefix, String key,  Class<T> clazz) {
		Jedis jedis = null;
		try {
			jedis =  jedisPool.getResource();
			//生成真正的key
			String realKey  = prefix.getPrefix() + key;
			String  str = jedis.get(realKey);
			T t =  stringToBean(str, clazz);
			return t;
		}finally {
			returnToPool(jedis);
		}
	}
	/**
	 * 查(判断是否存在)
	 * */
	public <T> boolean exists(KeyPrefix prefix, String key) {
		Jedis jedis = null;
		try {
			jedis =  jedisPool.getResource();
			//生成真正的key
			String realKey  = prefix.getPrefix() + key;
			return  jedis.exists(realKey);
		}finally {
			returnToPool(jedis);
		}
	}
	/**
	 * 工具:将 bean 转 String
	 */
	public static <T> String beanToString(T value) {
		if(value == null) {
			return null;
		}
		Class<?> clazz = value.getClass();
		if(clazz == int.class || clazz == Integer.class) {
			 return ""+value;
		}else if(clazz == String.class) {
			 return (String)value;
		}else if(clazz == long.class || clazz == Long.class) {
			return ""+value;
		}else {
			return JSON.toJSONString(value);
		}
	}
	/**
	 * 工具:string 转 bean
	 */
	public static <T> T stringToBean(String str, Class<T> clazz) {
		if(str == null || str.length() <= 0 || clazz == null) {
			 return null;
		}
		if(clazz == int.class || clazz == Integer.class) {
			 return (T)Integer.valueOf(str);
		}else if(clazz == String.class) {
			 return (T)str;
		}else if(clazz == long.class || clazz == Long.class) {
			return  (T)Long.valueOf(str);
		}else {
			return JSON.toJavaObject(JSON.parseObject(str), clazz);
		}
	}
	/**
	 * 关闭与 redis 的连接
	 */
	private void returnToPool(Jedis jedis) {
		 if(jedis != null) {
			 jedis.close();
		 }
	}
}

RabbitMQ

RabbitMQ消息队列的使用

1)添加依赖

		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-amqp</artifactId>
		</dependency>

2)定义配置类

配置信息

#rabbitmq
spring.rabbitmq.host=192.168.137.2
spring.rabbitmq.port=5672
spring.rabbitmq.username=guest
spring.rabbitmq.password=guest
spring.rabbitmq.virtual-host=/
spring.rabbitmq.listener.simple.concurrency= 10
spring.rabbitmq.listener.simple.max-concurrency= 10
spring.rabbitmq.listener.simple.prefetch= 1
spring.rabbitmq.listener.simple.auto-startup=true
spring.rabbitmq.listener.simple.default-requeue-rejected= true
spring.rabbitmq.template.retry.enabled=true 
spring.rabbitmq.template.retry.initial-interval=1000 
spring.rabbitmq.template.retry.max-attempts=3
spring.rabbitmq.template.retry.max-interval=10000
spring.rabbitmq.template.retry.multiplier=1.0

配置类

@Configuration
public class MQConfig {
	public static final String SECKILL_QUEUE = "seckill.queue";
	public static final String QUEUE = "queue";
	@Bean
	public MessageConverter getMessageConverter() {
		return new Jackson2JsonMessageConverter();
	}
	@Bean
	public Queue queue() {
		return new Queue(QUEUE, true);
	}

3)定义消息

@Setter
@Getter
public class SeckillMessage {
	private User user;
	private long goodsId;
}

4)定义生产者

@Service
public class MQSender {
	private static Logger log = LoggerFactory.getLogger(MQSender.class);
	@Autowired
	AmqpTemplate amqpTemplate;
	public void sendSeckillMessage(SeckillMessage mm) {
		String msg = RedisService.beanToString(mm);
		log.info("send message:"+msg);
		amqpTemplate.convertAndSend(MQConfig.SECKILL_QUEUE, msg);
	}
}

5)定义消费者

@Service
public class MQReceiver {
		private static Logger log = LoggerFactory.getLogger(MQReceiver.class);
		@Autowired
		RedisService redisService;
		@Autowired
		SeckillGoodsService goodsService;
		@Autowired
		OrderService orderService;
		@Autowired
		SeckillOrderService seckillOrderService;

		@RabbitListener(queues=MQConfig.SECKILL_QUEUE)
		public void receive(String message) {
			log.info("receive message:"+message);
			SeckillMessage sm  = RedisService.stringToBean(message, SeckillMessage.class);
			User user = sm.getUser();
			long goodsId = sm.getGoodsId();
			GoodsBo goods = goodsService.getSeckillGoodsBoByGoodsId(goodsId);
	    	int stock = goods.getStockCount();
	    	if(stock <= 0) {
	    		return;
	    	}
	    	//判断是否已经秒杀到了
	    	SeckillOrder order = seckillOrderService.getSeckillOrderByUserIdGoodsId(user.getId(), goodsId);
	    	if(order != null) {
	    		return;
	    	}
	    	//减库存 下订单 写入秒杀订单
			seckillOrderService.insert(user, goods);
		}
}

分布式技术:编程实践-分布式微服务-分布式基础

微服务架构图:编程实践-分布式微服务-微服务架构图

微服务组件:image-20240210163312090

SpringCloud


阿里巴巴nacos注册中心: 文档链接

  1. 依赖管理
<dependencyManagement>
	<dependencies>
		<dependency>
			<groupId>com.alibaba.cloud</groupId>
			<artifactId>spring-cloud-alibaba-dependencies</artifactId>
			<version>2.2.1.RELEASE</version>
			<type>pom</type>
			<scope>import</scope>
		</dependency>
	</dependencies>
</dependencyManagement>

Spring Boot 和Spring Cloud 版本适配

spring-boot-starter-parent
	<parent>
		<groupId>org.springframework.boot</groupId>
		<artifactId>spring-boot-starter-parent</artifactId>
		<version>2.5.3</version>
		<relativePath/> <!-- lookup parent from repository -->
	</parent>
spring-cloud-dependencies
	<dependencyManagement>
		<dependencies>
			<dependency>
		<groupId>org.springframework.cloud</groupId>
				<artifactId>spring-cloud-dependencies</artifactId>
				<version>2020.0.3</version>
				<type>pom</type>
				<scope>import</scope>
			</dependency>
		</dependencies>
	</dependencyManagement>
  1. 注册中心

nacos.discovery

引入依赖

<dependency>
   <groupId>com.alibaba.cloud</groupId>
   <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
 </dependency>

配置 Nacos Server 地址

spring:
 cloud:
  nacos:
   discovery:
    server-addr: 101.43.245.198:8848

使用 @EnableDiscoveryClient 注解开启服务注册与发现功能

@EnableDiscoveryClient

为每个服务增加添加基本配置信息(服务有名字才能注册上去)

spring:
  application:
  name: upcmall-product
server:
  port: 11000
  1. 远程调用

所使用的组件是:springcloud.openfeign

引入依赖

<!-- https://mvnrepository.com/artifact/org.springframework.cloud/spring-cloud-starter-openfeign -->
<dependency>
	<groupId>org.springframework.cloud</groupId>
	<artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>

开启feign功能

@EnableFeignClients(basePackages=“com.upc.upcmall.product.feign”)

声明远程接口

@FeignClient(“upcmall-ware”)
public interface WareFeignService{
	@PostMapping(“ware/waresku/skus”)
	Public Resp<List<SkuStockVo>> skuWareInfos(@RequestBody List<Long> skuIds);
}

编写一个接口,告诉SpringCloud这个接口需要调用远程服务


  1. 配置中心

所使用的组件是 nacos.config

引入依赖

<dependency>
	<groupId>com.alibaba.cloud</groupId>
	<artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId>
</dependency>

创建配置文件bootstrap.properties

spring.application.name=upcmall-coupon
spring.cloud.nacos.config.server-addr=101.43.245.198:8848

在配置中心添加一个数据集(Data Id)upcmall-coupon.properties(应用名.properties)

coupon.user.name=”李四”
coupon.user.age=”18”

配置配置文件application.properties

coupon.user.name=”张三”
coupon.user.age=”20”

添加测试接口

@Value("${coupon.user.name}")
private String name;
@Value("${coupon.user.age}")
private Integer age;
@RequestMapping("/test")
public R test(){
	return R.ok().put("name",name).put("age",age);
}

添加注解

@RefreshScope //动态获取并刷新配置
@Value(“${配置项的名}) //获取配置项

在配置中心统一所有配置bootstrap.properties

spring.cloud.nacos.config.ext-config[0].data-id=datasource.yml
spring.cloud.nacos.config.ext-config[0].group=dev
spring.cloud.nacos.config.ext-config[0].refresh=true
spring.cloud.nacos.config.ext-config[1].data-id=mybatis.yml
spring.cloud.nacos.config.ext-config[1].group=dev
spring.cloud.nacos.config.ext-config[1].refresh=true
spring.cloud.nacos.config.ext-config[2].data-id=other.yml
spring.cloud.nacos.config.ext-config[2].group=dev
spring.cloud.nacos.config.ext-config[2].refresh=true
  1. 网关

使用的组件是:spring.cloud.gateway

引入依赖,引入common依赖并剔除springboot.web依赖,解决依赖冲突

<dependency>
	<groupId>com.upc.upcmall</groupId>
	<artifactId>upcmall-common</artifactId>
	<version>1.0-SNAPSHOT</version>
	<exclusions>
		<exclusion>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-web</artifactId>
		</exclusion>
	</exclusions>
</dependency>

添加注解,取消数据源自动配置

@SpringBootApplication(exclude = {DataSourceAutoConfiguration.class})

配置文件application.properties

spring.application.name=upcmall-gateway
spring.cloud.nacos.discovery.server-addr=101.43.245.198:8848
server.port=88

配置文件bootstrap.properties

spring.application.name=upcmall-gateway
spring.cloud.nacos.config.server-addr=101.43.245.198:8848
spring.cloud.nacos.config.namespace=65ef2335-6de9-46c1-9807-e688c87d09e6
spring.cloud.nacos.config.group=dev

配置predicate factory application.yml

spring:
 cloud:
  gateway:
   routes:
    - id: baidu_route
      uri: https://baidu.com
      predicates:
    	- Query=url,baidu
    - id: qq_route
      uri: https://qq.com
      predicates:
    	- Query=url,qq

浏览器中测试:http://localhost:88/?url=qq

  1. 事件驱动

依赖

<!--集成消息中间件:spring-cloud-stream、kafka-->
<dependency>
	<groupId>org.springframework.cloud</groupId>
	<artifactId>spring-cloud-stream</artifactId>
</dependency>

spring cloud stream 配合kafka的使用见git仓库

centos7中安装kafka

依赖

<dependency>
	<groupId>org.springframework.cloud</groupId>
	<artifactId>spring-cloud-starter-stream-kafka</artifactId>
</dependency>

配置

spring:
  cloud:
    stream:
      kafka:
        binder:
          brokers: 192.168.137.41:9092
      bindings:
        input:
          destination: accountChangeTopic
          contentType: application/json
        output:
          destination: accountChangeTopic
          contentType: application/json

Maven


v3.8.2常用命令

# 删除target
mvn clean
# 编译
mvn compile
# 打包
mvn package -DskipTests=ture
# 安装到本地仓库
mvn install
# 安装到远程仓库
mvn deploy
# 打包并运行springboot
mvn spring-boot:run
# 检验资源是否可用
mvn validate
# 测试
mvn test

Docker


教程:https://docs.docker.com/language/java/develop/
Docker仓库:https://hub.docker.com/repository/docker/zhoujiakai/cicdtest/general
Github仓库:https://github.com/zhoujiakai/cicdtest

使用最新版本 v24.0.6,分为3步:定义Dockerfile、docker build、docker run。分为8个步骤:

image-20240210181348735
  1. 打包镜像

定义Dockerfile

环境准备:jdk8_202,mvn3,git

## syntax=docker/dockerfile:1
FROM eclipse/ubuntu_jdk8:latest

WORKDIR /app
COPY pom.xml ./
COPY src ./src

RUN mvn clean install

CMD ["java", "-jar", "./target/cicdtest-1.0.0-SNAPSHOT.jar"]

构建

cd cicdtest
docker build --tag zhoujiakai/cicdtest .
docker images

2)运行容器

docker run \
--name mypro \
 -d -p 8080:8080 \
zhoujiakai/cicdtest:latest

docker run \

–name mypro \

-d -p 8080:8080 \

zhoujiakai/cicdtest:latest

3)组合服务

持久化存储:创建2个卷

docker volume create mysql_data
docker volume create mysql_config

创建一个网络:mysqlnet

docker network create mysqlnet

运行mysql容器:

docker run -it --rm -d -v mysql_data:/var/lib/mysql \
-v mysql_config:/etc/mysql/conf.d \
--network mysqlnet \
--name mysqlserver \
-e MYSQL_USER=petclinic -e MYSQL_PASSWORD=petclinic \
-e MYSQL_ROOT_PASSWORD=root -e MYSQL_DATABASE=petclinic \
-p 3306:3306 mysql:8.0

更新Dockerfile文件:

## syntax=docker/dockerfile:1
FROM eclipse/ubuntu_jdk8:latest
WORKDIR /app
COPY pom.xml ./
COPY src ./src

RUN mvn clean install

CMD ["java", "-jar", "./target/cicdtest-1.0.0-SNAPSHOT.jar"]

创建docker-compose.dev.yml

version: '3.8'
services:
  cicdtest:
    build:
      context: .
    ports:
      - "8080:8080"
    volumes:
      - ./:/app
    depends_on:
      - mysqlserver

  mysqlserver:
    image: mysql:8.0
    ports:
      - "3306:3306"
    environment:
      - MYSQL_ROOT_PASSWORD=
      - MYSQL_ALLOW_EMPTY_PASSWORD=true
      - MYSQL_USER=cicdtest
      - MYSQL_PASSWORD=cicdtest
      - MYSQL_DATABASE=cicdtest
    volumes:
      - mysql_data:/var/lib/mysql
      - mysql_config:/etc/mysql/conf.d
volumes:
  mysql_data:
  mysql_config:

构建服务:

docker compose -f docker-compose.dev.yml up --build -d

4)CICD

1) Create a new repository on GitHub.
https://github.com/zhoujiakai/cicdtest

2) Define the GitHub Actions workflow.
DOCKERHUB_USERNAME:zhoujiakai
(dockerhub中)clockboxci:dckr_pat_sSv53yr3x1Vtk269DqsHYg3-U20
DOCKERHUB_TOKEN:dckr_pat_sSv53yr3x1Vtk269DqsHYg3-U20

3) Run the workflow.
name: ci

on:
  push:
    branches:
      - "main"

jobs:
  build:
    runs-on: ubuntu-latest
    steps:
      -
        name: Checkout
        uses: actions/checkout@v4
      -
        name: Login to Docker Hub
        uses: docker/login-action@v3
        with:
          username: ${{ secrets.DOCKERHUB_USERNAME }}
          password: ${{ secrets.DOCKERHUB_TOKEN }}
      -
        name: Set up Docker Buildx
        uses: docker/setup-buildx-action@v3
      -
        name: Build and push
        uses: docker/build-push-action@v5
        with:
          context: .
          file: ./Dockerfile
          push: true
          tags: ${{ secrets.DOCKERHUB_USERNAME }}/cicdtest:latest

测试运行

docker run \
--name mypro \
 -d -p 8080:8080 \
zhoujiakai/cicdtest:latest

成功

使用docker运行打包好的java文件

  1. 将jar文件放到:服务器

位置:“/tmp/dockertmp”

  1. 创建Dockerfile

教程:docker官方文档,博客csdn @ 小刘不想敲代码

创建“Dockerfile”并添加以下内容

## 基础镜像使用java
FROM zhoujiakai/openjdk:jdk18
## 作者
MAINTAINER zhoujk
## VOLUME 指定临时文件目录 /tmp 在主机 /var/lib/docker 目录下创建一个临时文件并连接到容器的 /tmp
VOLUME /tmp
## 将jar包添加到容器中并更名为 callback_docker.jar(这个最重要!!!)
ADD oss-callback-server-demo.jar callback_docker.jar
## 运行jar包
RUN bash -c 'touch /callback_docker.jar'
ENTRYPOINT ["java","-jar","/callback_docker.jar"]
## 暴露端口
EXPOSE 9000
  1. 创建docker镜像
docker build -t callback_docker:1.6 .
  1. 运行docker容器
docker run --rm -d -p 9000:9000 callback_docker:1.6 --name callback1
docker run --rm -it -p 9000:9000 callback_docker:1.6 --name callback1
  1. 有个类没有找到

org/eclipse/jetty/server/Handler

Kubesphere


使用版本v4.0.0,Kubesphere结构如下:

admin:默认管理员用户,在 KubeSphere平台具有所有权限,并可以根据需要创建其他用户。
角色和用户:将不同的权限组合抽象成角色。角色分为:平台角色、集群角色、企业空间角色、项目角色
用户: 每一个用户都只属于一种角色,拥有角色所定义的操作系统资源的权限。
集群
企业空间
项目
多集群项目
DevOps项目

k8s-v1.28.0


学习的思路:基本概念 → \rightarrow 最佳实践 → \rightarrow 应用到项目中

k8s基本组件

master节点:
	etcd(2379/2380):分布式存储机制,保存整个集群的状态
	API server(6443):对外提供操作和访问etcd的API
	Scheduler(10251):调度Pod资源到相应的机器上
	Controller Manager(10252):自动观察和维护集群状态
worker节点:
	Controller Runtime:下载镜像和运行容器
	Pod:k8s的基本调度单位
	kubelet(10250):与master节点上的API server进行交互,接收指令执行操作
	kube-proxy(10256):负责对Pod进行寻址和负载均衡
网络通讯:	
dashboard(8443):用户操作k8s集群是通过kubectl命令行工具或者dashboard;
Pod之间进行通讯时通过集群内部覆盖网络Overlay Network;
外部流量进行集群访问Pod则是通过负载均衡Load Balander设备进行。

k8s数据字典

如何使用k8s:image-20240210183102964

Cluster:整个kubernetes集群,使用kubernetes统一管理整个集群的资源。

Deployment:部署应用程序

使用 kubectl create deployment 命令在 Kubernetes 上部署应用,例如:
kubectl create deployment kubernetes-bootcamp --image=gcr.io/google-samples/kubernetes-bootcamp:v1
kubectl get deployments列出所有部署

Service:使用service整合多个pod以及向外部暴露service服务,在运行deployment时使用–expose参数创建一个service

Replicas:在运行kubectl run命令时使用–replicas参数来设置副本数。

外部化应用配置:使用 Kubernetes ConfigMaps 和 Secrets 设置环境变量, 然后在 MicroProfile config 中使用它们。

k8s常用命令

删除资源:kubectl delete pod/redis configmap/example-redis-config
删除services:kubectl delete services my-service
删除deployment:kubectl delete deployment hello-world

Jenkins


官网教程:https://www.jenkins.io/doc/book/installing/linux/#debianubuntu

  • 4
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值