有点慌,新公司项目构建用的Gradle

news2024/11/16 1:53:49

        入职新公司,构建项目的工具用的gradle,以前没用过,看到一个build.gradle,点进去,心里一句我曹,这写的都是些什么玩意,方得一批,赶紧去补了下课。 

        好吧,先学点语法,这时我从屏幕倒影看到背后新来的老哥电脑屏幕上显示了在百度groovy,马萨卡??

Grooy篇

Groovy安装

        这玩意和安装java差不多啊,先找到官方下载页:groovy官方下载地址

        找了个现在的稳定版本就开始熟悉基础语法

         配置一下系统变量,这简单,win11点击开始,去找到设置

 接着点呗

 

建一个 GROOVY_HOME=本地路径安装路径  的变量 ,再找到Path变量,编辑它,追尾(呸),在尾部添加一个变量,像这样

好了,到此为止,去cmd验证一下吧,win+R,输入cmd

在控制台输入groovy -v

显示版本信息就安装完成啦!

Groovy基础语法

先建个groovy项目,这就不介绍了吧。这有点不搞基(输入法好像泄露了什么),groovy是基于JVM的,所以很多语法学起来没啥压力,确实groovy提供了一些比java更好用的方法

现在假装我们项目建好了,直接开整,写个hello world吧

package com.zab.groovytest

println 'hello world'

 啊这,好像挺简单的

Groovy常用数据类型

简单,直接上代码

package com.zab.groovytest

int a = 111
println a.class

double b = 1.1
println b.class

def c = 200
println c.class
//弱类型定义,后续可更改类型
def d = 1.122
println d.class
d = 1
println d.class

//单引号定义字符串,格式需要自己用转义字符定义
def s1 = 'za\nb1'
println s1
println s1.class

//双引号定义字符串,用于可扩展字符串
def s2 = "zab2"
def s22 = "zab2${s2}"
def s222 = "zab2${100+100}"
println s2
println s2.class
println s22.class
println s222.class

//三引号定义字符串,格式直接换行都行,加个反斜杠输出就和实际一致,不加会多一个空行
def s3 = '''\
za
b3'''
println s3
println s3.class

def s4 = "higroovy"
println s4.center(12)

println s4.center(12, 'ab')
println s4.padRight(11, 'ab')
println s4.reverse()
//首字母大写
println s4.capitalize()
def s5 = "123"
//转换类型
println s5.toInteger().class

//截取
def s6 = "groovy"
println s6[2]
println s6[2..5]

//字符串减法
def s7 = "groovyhello"
println s7.minus("hello")
println s7 - "groovy"

 代码挺简单,大家拷过去,跑一下,就假装自己会了吧,反正我们要学的是gradle,这jb简单得抠脚的基础语法,看看就行。

Groovy类、方法定义

定义类同时也可以定义方法,也是很简单,可以直接通过代码看懂

package com.zab.groovytest

class Student {
    String name;
    Integer age;

    Student(String name, Integer age){
        this.name = name;
        this.age = age;
    }

    Student(){

    }

    //方法的定义
    def sayHello(){
        println "hello ${name}"
    }
    //默认返回最后一行
    def sayHello2(param1, param2){
        "hello ${param1} ----- ${param2}"
    }

    //静态方法
    static def sayHello3(){
        println "hello static"
    }

    //默认方法,当调用方法不存在时,会调用该方法
    //有该方法就不会调用 invokeMethod
    def methodMissing(String name, args){
        println "method missing ${name}"
    }

    //invokeMethod的使用,当methodMissing方法不存在时,会调用该方法
    @Override
    def invokeMethod(String name, args){
        println "invokeMethod ${name}"
    }
}

然后我们看看如何去new这个类

package com.zab.groovytest

//定义类的方法
//无参构造
def zhangsan = new Student(name: "zhangsan", age: 10)
def lisi = new Student(name: "lisi")

//有参构造
def wangwu = new Student("wangwu", 20)
def zhaoliu = [name: "zhaoliu", age: 30] as Student
Student tianqi = ["tianqi", 20]

//属性的取值
println "名字:${zhangsan.name}, 年龄:${zhangsan.age}"
println "名字:${zhangsan.getName()}, 年龄:${zhangsan.getAge()}"

tianqi.sayHelloo()

这里注意,我调用了一个sayHelloo方法,这个方法不存在,会调用到methodMissing,如果类里面没定义methodMissing,会调用invokeMethod

Groovy集合

package com.zab.groovytest

//定义集合
def list = [1,2,3,4,5]
println list.class
println list.size()

//定义数组
def array = [1,2,3,4,5] as int[]
println array.class
println array.size()

//列表的使用
//添加元素
list.add(6)
println list
list.leftShift(7)
println list
list << 8
println list
def newList = list + 9
println newList

//按照索引删除元素
newList.remove(0)
println newList

//按照元素删除元素
newList.remove((Object)8)
println newList
newList.removeElement(4)
println newList

//按照条件删除元素
newList.removeAll({it % 2 == 0})
newList.removeIf({it > 5})
println newList
def newList1 = newList - [3, 5]
println newList1

//排序
newList = [1,-3,5,2,-4]
newList.sort()
println newList
//按照绝对值排序
newList.sort({Math.abs(it)})
println newList
//按照长度排序
def listStr = ["abc","ddef","12f3","45ddd6"]
listStr.sort({it.length()})
println listStr

//查找
println newList.findAll({it > 0})
println newList.find({it > 0})
//判断是否存在
println newList.any({it > 0})
//判断是否全部满足
println newList.every({it > 0})
//统计
println newList.count({it > 0})

 一句话点评groovy的集合,很灵活,很脚本(一个功能,这样写也可以,那样写也可以)

Groovy Map

package com.zab.groovytest
//定义map
def map = ['张三':18, '李四':20, '王五':22]
println map.class
println map

//添加元素
map.put('赵六', 24)
println map
map['田七'] = 26
println map
map.'newMap' = ['x':1, 'y':2]
println map
//map单引号可以不写
def map2 = [张三:18, 李四:20, 王五:22]
println map2
println map2.getClass()


//遍历map
println "--------遍历map--------"
for (i in map2) {
    println i
    println i.key
    println i.value
}
map2.each{
    println it
    println it.key
    println it.value
}
//带下标的遍历
println "--------带下标的遍历--------"
map2.eachWithIndex{ key,value,index ->
    println key
    println value
    println index
}

//查找map3
println "--------查找map3--------"
def map3 = [
        张三:['score':88,'sex':'男'],
        李四:['score':78,'sex':'女'],
        王五:['score':68,'sex':'女'],
        赵六:['score':58,'sex':'男']
]
//查找score大于60的
println map3.findAll{it.value.score > 60}
println map3.find{it.value.score > 60}
//查找score大于60的,sex为女的数量
println map3.count{it.value.score > 60 && it.value.sex == '女'}
//分组,低于60分的为不及格,60-80为中等,80以上为优秀
println map3.groupBy{
    if (it.value.score < 60) {
        '不及格'
    } else if (it.value.score < 80) {
        '中等'
    } else {
        '优秀'
    }
}
//排序,按照成绩从高到低
println map3.sort{it.value.score}
//排序,按照成绩从低到高
println map3.sort{it.value.score}.reverse()

一句话点评groovy的Map,很灵活,很脚本(一个功能,这样写也可以,那样写也可以),等等这句话我好像刚刚看到过

Groovy Range

这个是java没有的功能,有点像个集合的变种

package com.zab.groovytest

//定义范围
def r = 2..5
println r.class

def r1 = 3..<8
println r1.size()

//范围的基本操作,实际上范围就是一个列表的实现
println r.contains(3)
println r.from
println r.to

//范围的遍历
for (i in r) {
    println i
}
r1.each {println it}

//范围的转换
def list = r.toList()

Groovy MetaClass        

这是一个动态为class添加方法或者字段的东西,真是一些奇奇怪怪的知识

package com.zab.groovytest

//动态为Student添加方法
Student.metaClass.sayHello4 = {
    println "hello4"
}

//动态为Student添加静态方法
Student.metaClass.static.sayHello5 = {
    println "hello5"
}

//动态为Student添加属性
Student.metaClass.sex = "女"

def student = new Student("zhangsan", 18)

//调用动态添加的方法
student.sayHello4()
Student.sayHello5()
println student.sex

Groovy Closure(闭包)

这个好重要,认真学习一下

package com.zab.groovytest

//本质上闭包就是一个代码块,可以把闭包理解为一个匿名函数
//闭包的定义
def closure = {
    println "hello closure"
}
//闭包的调用
closure()
closure.call()

//闭包的参数
def closure2 = {String name ->
    println "hello ${name}"
}
closure2("")
closure2.call("lisi")

def closure3 = {String name, int i ->
    println "hello ${name} ${i}"
}
closure3("lisi", 10)

//闭包的默认参数, it
def closure4 = {
    println "hello ${it}"
}
closure4("lisi")

//闭包的返回值
def closure5 = {
    return "hello closure"
}
println closure5()

//闭包的循环,直接点进去看源码
1.upto(10, closure4)
//这种写法也可以
1.upto(10){println it}

//从1加到100,闭包的循环
def sum = 0
1.upto(100, {sum += it})
println sum

//downto的使用
10.downto(1, {println it})

//times 的使用,指定次数循环
10.times({println it})

def s = "hello groovy 2023"
//each的使用
s.each({println it})
//find的使用
println s.find({it.isNumber()})
//findAll的使用
println s.findAll({it.isNumber()})
//any的使用
println s.any({it.isNumber()})
println s.any {it.isNumber()}
//every的使用
println s.every({it.isNumber()})
//collect的使用
println s.collect({it.toUpperCase()})

//闭包的参数:this,owner,delegate
//this:指向当前闭包
//owner:指向当前闭包所属的对象
//delegate:指向当前闭包所属的对象,但是可以被修改
def closure6 = {
    println "this: ${this}"
    println "owner: ${owner}"
    println "delegate: ${delegate}"
}
closure6()
//一般这三个参数都是一样的,只有当闭包中包含闭包的时候,不一样
/**
 * c1 this: com.zab.groovytest.GroovyClosure@162be91c
 * c1 owner: com.zab.groovytest.GroovyClosure@162be91c
 * c1 delegate: com.zab.groovytest.GroovyClosure@162be91c
 * c2 this:com.zab.groovytest.GroovyClosure@162be91c
 * c2 owner:com.zab.groovytest.GroovyClosure$_run_closure18@31e3250d
 * c2 delegate:xxx
 */
def c1 = {
    println "c1 this: ${this}"
    println "c1 owner: ${owner}"
    println "c1 delegate: ${delegate}"
    def c2 = {
        println "c2 this:"+ this
        println "c2 owner:"+ owner
        println "c2 delegate:"+ delegate
    }
    c2.delegate = "xxx"
    c2()
}
c1.call()


Groovy switch和for

package com.zab.groovytest
//groovy的switch非常灵活
def a = 10

switch (a){
    case Integer:
        println "a is Integer"
        break
    case "abc":
        println "a is abc"
        break
    case [100,10]:
        println "a in 10,100"
        break
    case 1.1:
        println "a is 1.1"
        break
    case 1..100:
        println "a in 1-100"
        break
    default:
        println "a is nothing"
        break
}
//普通范围
println "--------普通范围循环--------"
for (i in 0..5) {
    println i
}
println "--------普通范围小于--------"
for (i in 0..<5) {
    println i
}
println "--------列表循环--------"
for (i in [10,20,30,40,50]) {
    println i
}
println "--------map循环--------"
for (i in [10:"hh",20:"jj",30:"kk"]) {
    println i
    println i.value
}

Groovy 文件操作

package com.zab.groovytest

//读取文件
def file = new File("d://json.txt")
//方式一,readLines
def lines = file.readLines()
println lines

//方式二,eachLine
file.eachLine{
    println it
}
//方式三,getText
println file.getText()

//写入文件
def file2 = new File("d://json2.txt")
file2.write("hello world")

//定义一个方法,参数一是源文件,参数二是复制的文件,实现copy功能
def copyFile(String srcFileStr, String destFileStr){
    //如果目标文件不存在,则创建
    def destFile = new File(destFileStr)
    if(!destFile.exists()){
        destFile.createNewFile()
    }
    //读取源文件
    def srcFile = new File(srcFileStr)
    def lines = srcFile.readLines()
    //写入目标文件
    destFile.write(lines.join("\n"))
}

copyFile("d://json.txt", "d://json3.txt")

//读取文件部分
def file3 = new File("d://json.txt")
file3.withReader { reader ->
    char[] buffer = new char[9]
    reader.read(buffer, 0, 9)
    println buffer
}

Groovy JSON操作

package com.zab.groovytest

import groovy.json.JsonOutput
import groovy.json.JsonSlurper

//将json字符串转换为对象
def str = '{"name":"zhangsan", "age":18}'
def student = new JsonSlurper().parseText(str)
println student

//将对象转换为json字符串
def stu = new Student("lisi", 20)
println JsonOutput.prettyPrint(JsonOutput.toJson(stu))

json转对象,对象转json还是挺常见一操作,用groovy操作,也是挺简单的

Gradle篇

安装挺简单,和groovy类似

Gradle新建项目

 

新建项目,需要配置一下gradle为本地安装的版本,随便指定一下Gradle user home为常用的maven本地仓库地址

 我这边建完项目就很简单

现在加点常用目录

 

看起来正常熟悉一些了,然后build.gradle其实就相当于maven管理项目时,项目中的pom.xml文件

新项目,在配置文件中加一点防止乱码的总有用的

//加一点防止乱码的配置
tasks.withType(JavaCompile) {
    options.encoding = "UTF-8"
}

Gradle 学习

现在进入正题

Gradle 生命周期

Gradle的生命周期分三个阶段: 初始化阶段、配置阶段、执行阶段。

  • 初始化阶段

通过settings.gradle判断有哪些项目需要初始化,加载所有需要初始化的项目的build.gradle文件并为每个项目创建project对象

  • 配置阶段

执行各项目下的build.gradle脚本,完成project 的配置,并且构造Task任务依赖关系图以便在执行阶段按照依赖关系执行Task中的配置代码

  • 执行阶段

通过配置阶段的Task图,按顺序执行需要执行的任务中的动作代码,就是执行任务中写在doFirst或doLast中的代码。

Gradle Project

一个project代表一个正在构建的组件(jar或者war),构建时,gradle会基于这个配置文件(build.gradle)搞个实例对象出来(org.gradle.api.Project),并且通过对象的变量来隐式调用对象的方法或者字段。

Project有哪些属性呢?

我有点好奇,键盘按住ctrl,鼠标点了一下group

就,就打开了这个project类,跳转到setGroup方法了,这根据我浑厚的java功底,我知道这个group就可以为project赋值了啊!那么version我也搞懂了。

于是,我好像慢慢能看懂这个最开始有点我曹的文件了。于是我又点了一下,repositories,它那个跳啊

这语法就是说,我需要传一个参数给repositories呗,参数是一个闭包呗,闭包就是一个代码块呗 

只要是个闭包就也能点吧,我点点点。。。

这,,看起来就像要去https://repo.maven.apache.org/maven2/仓库拉代码呀(所以,gradle是没有自己的中央仓库,用的别人的,还妄图干掉maven,做人要摸自己左咪咪呀)

属性有哪些其实Project里面set方法能看出来一些,但是有些隐式的字段没找到定义在哪

名称类型默认值
projectProjectProject实例
nameString项目目录的名称。
pathString项目的绝对路径。
descriptionString项目的描述。
projectDirFile包含生成脚本的目录。
buildDirFileprojectDir/build
groupObject未指定
versionObject未指定
antAntBuilderAntBuilder实例

我挑了一些,用刚刚学到的groovy hello world语法,打印一下,点构建工具的build,会执行println

Gradle Task

 gradle的task在构建执行过程中,会被封装成org.gradle.api.Task对象,主要包括任务的动作和任务依赖。

task初识

我现在定义一个task

task(t1, {
    //分个组
    group("myGroup")
    println "t1"

    //动作
    doLast {
        println "doLast"
    }
    doFirst {
        println "doFirst"
    }
})

可以看到,分组和task都在右侧有显示了,并且我双击了task,它也执行了

 task新建的几种方式

//定义方式1:
task(t1,{
    group("mytask")
    //配置代码
    println '我是任务1'
    //动作代码
    doFirst {
        println '在任务t1执行前操作的动作代码'
    }
    //动作代码
    doLast {
        println '在任务t1执行后操作的动作代码'
    }
})
//定义方式2:
task t2 {
    group("mytask")
    //配置代码
    println '我是任务2'
    //动作代码
    doFirst {
        println '在任务t2执行前操作的动作代码'
    }
    //动作代码
    doLast {
        println '在任务t2执行后操作的动作代码'
    }
}

//定义方式3:
tasks.create('t3'){
    group("mytask")
    //配置代码
    println '我是任务3'
}

//定义方式4:
tasks.register('t4'){
    group("mytask")
    //配置代码
    println '我是任务4'
}

//定义方式5:
tasks{
    task t5{
        group("mytask")
        //配置代码
        println '我是任务5'
    }
}

//定义方式6
3.times{index ->
    task("task${index}"){
        group("mytask")
        //配置代码
        println 'task${index}'
    }
}

定义方式5有几个特点: 

  • 在build阶段的配置过程中不执行
  • 在任务的执行阶段的配置过程中是执行的
  • 配置代码的执行时机是落后于用task方式配置的

task 依赖

//任务依赖,a任务是被别的任务依赖的
task a{
    doFirst {
        println '我是任务a'
    }
}
//表示b任务依赖a任务,a任务放入参数传递
task b(dependsOn:a){
    doFirst {
        println '我是任务b'
    }
}
//表示c任务依赖a任务,依赖方式在任务内部进行依赖
task c{
    dependsOn 'b'  
    doFirst {
        println '我是任务c'
    }
}

task d{
    doFirst {
        println '我是任务d'
    }
}

//d任务外部依赖c,这种方式也可以
d.dependsOn c   

Gradle 自定义jar

接下来的实例在工作中很可能用得上了,我们要实现项目A打个jar,在项目B中使用

  • 搞个新gradle项目,我这里命名为gradle-plugin

细节略,前面有

  • 配置插件

核心配置如下

plugins {
    id 'java-library'
    id 'maven-publish'
}
publishing {
    publications {
        mavenJava(MavenPublication) {
            from components.java
        }
    }

    repositories{
        mavenLocal()
    }
}

然后我们刷新项目,就可以看到有一个task:publishing

  • 发布需要被引用的jar

我们双击一下publishToMavenLocal,由于我的配置是配置了本地maven仓库的,而不是走的默认gradle仓库地址,所以我在以下目录能看到打包好的jar

 项目没啥内容,就是定义了一个类Student,主要为了演示jar在别的项目中能引用

package com.zab.gradleplugin;

public class Student {
    private String name;
    private String age;

    public Student(String name, String age) {
        this.name = name;
        this.age = age;
    }

    public String getName() {
        return this.name;
    }

    public String getAge() {
        return this.age;
    }

    public void setName(String name) {
        this.name = name;
    }

    public void setAge(String age) {
        this.age = age;
    }
}
  • 其他项目引用

核心配置如下

repositories {
    mavenLocal()
    mavenCentral()
}
dependencies {
    testImplementation 'org.junit.jupiter:junit-jupiter-api:5.8.1'
    testRuntimeOnly 'org.junit.jupiter:junit-jupiter-engine:5.8.1'
    implementation(group: 'org.zab', name: 'gradle-plugin', version: '1.0-SNAPSHOT')
}

主要是    mavenLocal()  和   implementation(group: 'org.zab', name: 'gradle-plugin', version: '1.0-SNAPSHOT')

现在开始使用

package com.zab.test;

import com.zab.gradleplugin.Student;

public class Test {
    public static void main(String[] args) {
        Student student = new Student("zhangsan", "18");
        System.out.println(student.getName());
    }
}

Gradle 插件

我们用脚本自定义插件,需要在build.gradle里面编写


class MyPlugin implements Plugin<Project> {
    @Override
    void apply(Project project) {
        project.task('myPluginTask') {
            doLast {
                println 'myPluginTask'
            }
        }
    }
}

apply plugin: MyPlugin

然后刷一把,可以看到插件成功创建

我们也可以自己在其他目录写,这样都可以用

注意是创建目录,按照以下目录结构创建目录

build.gradle放到src下,编写如下内容:

apply plugin:'groovy'

我们在编写一个新的可以公用的插件

import org.gradle.api.Plugin;
import org.gradle.api.Project;

class MyFirstPlugin implements Plugin<Project>{
    @Override
    public void apply(Project project){
        project.task("MyFirstPlugin").doLast(task -> {
            System.out.println("hello MyFirstPlugin");
        });
    }
}

 然后在项目中引用一下

apply plugin: MyFirstPlugin

就可以使用了,如下图,刷新一下项目,就可以看到新插件

 Gradle 版本冲突解决

在maven管理的项目中,有两个比较重要的解决依赖冲突的原则

  • 第一原则:最短路径优先原则

最短路径优先就是说项目依赖关系树中路径最短的版本会被使用。
假设A、B、C三个项目之间的依赖关系是A->B->C->D(2.0)和A->C->(D1.0),那么D(1.0)会被使用,因为A通过C到D的路径更短

  • 第二原则:最先声明原则

依赖路径长度是一样的的时候,第一原则不能解决所有问题。比如这样的依赖关系:A-B-D(1.0),A-C-D(2.0),D(1.0)和D (2.0)的依赖路径长度是一样的都为2,那么到底谁会被解析使用呢?

在maven 20.8及之前的版本中,这是不确定的,但是maven20.9开始,为了尽可能避免构建的不确定性,maven定义了依赖调解的第二原则:第一声明者优先。在依赖路径长度相等的前提下,在中依赖声明的顺序决定了谁会被解析使用。

gradle项目中,有一个自动解决方案,即使版本高的优先选用

做个简单实验,我们知道spring-web-mvc是依赖了spring-aop的,这样一个高低版本组合,再看看具体依赖就知道依赖的哪个版本了

    implementation(group: 'org.springframework', name: 'spring-aop', version: '5.1.3.RELEASE')
    implementation(group: 'org.springframework', name: 'spring-webmvc', version: '5.1.13.RELEASE')

现在我们排除掉spring-aop依赖

    implementation(group: 'org.springframework', name: 'spring-webmvc', version: '5.1.13.RELEASE', {
        exclude group: 'org.springframework', module: 'spring-aop'
    }
    )

 可以看到,用上了老版本了

还有一些比较常用的配置,比如所有jar不做自动冲突解决

configurations.all{
    resolutionStrategy{
        failOnVersionConflict()
    }
}

强制覆盖某个版本

configurations.all(
    resolutionStrategy{
        force 'org.springframework:spring-beans:5.3.12
    }
}

Gradle 多模块构建

  • 先创建两个模块

  •  gradle项目下的配置文件修改配置文件
//多模块配置 1
allprojects {
    apply plugin: 'java'

    project.group = 'com.zab'
    version = '1.0-SNAPSHOT'
}
//多模块配置 2
subprojects {
    repositories {
        mavenLocal()
        mavenCentral()
    }

    dependencies {
        testImplementation 'org.junit.jupiter:junit-jupiter-api:5.8.1'
        testRuntimeOnly 'org.junit.jupiter:junit-jupiter-engine:5.8.1'
        implementation(group: 'org.zab', name: 'gradle-plugin', version: '1.0-SNAPSHOT')
        implementation(group: 'org.springframework', name: 'spring-aop', version: '5.1.3.RELEASE')
        implementation(group: 'org.springframework', name: 'spring-webmvc', version: '5.1.13.RELEASE', {
            exclude group: 'org.springframework', module: 'spring-aop'
        }
        )

    }
}

主要是把插件、project.group、version 等字段移到了allprojects ,依赖和仓库配置移到了subprojects 

  • 模块之间的依赖

例如:subproject1依赖subproject02

dependencies {
    implementation project(':subproject02')
}

这就可以啦,然后刷一把依赖

好了,到这里基本上遇到公司用gradle构建的项目我就没那么慌了 ~~ 我又开始了愉快的增删改查,吼吼

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/817493.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

根据选择内容自动生成正则表达式

地址: https://regex.ai/ 如何使用? 比如我这里有个需求: 提取图片路径中的文件名 https://wx4.sinaimg.cn/mw1024/0040jbadly1hg5nk0l3gtj62c0340kjl02.jpg 提取出0040jbadly1hg5nk0l3gtj62c0340kjl02.jpg 数据越多越准确 左边提供数据, 右边给出需要提取的数据, 点击run&…

地产变革中,物业等风来

2023年7月&#xff0c;也许是中国房地产行业变局中的一个大拐点。 中信建投研报表示&#xff0c;政治局会议指出当前我国房地产形势已发生重大变化&#xff0c;要适时调整优化政策&#xff0c;为行业形势定调……当前房地产行业β已至。 不久前&#xff0c;国家统计局公布了2…

Mag-Fluo-4 AM,镁离子荧光探针,是一种有用的细胞内镁离子指示剂

资料编辑|陕西新研博美生物科技有限公司小编MISSwu​ PART1----产品描述&#xff1a; 镁离子荧光探针Mag-Fluo-4 AM&#xff0c;具细胞膜渗透性&#xff0c;对镁离子&#xff08;Mg2&#xff09; 和钙离子&#xff08;Ca2&#xff09;的 Kd 值分别是 4.7mM 和 22mM&#xff0c…

运维:Multipass软件让你的虚拟机管理更简单高效

一、Multipass是什么&#xff1f; 官网&#xff1a;https://multipass.run/ 一提到虚拟机大家一般都会想到VMvare和Virtual Box这两个的虚拟机软件&#xff0c;这两个软件一个比较麻烦的地方是安装完虚拟机以后还需要下载操作系统镜像。小编偶然间发现了Multipass。这款轻量级的…

Flowable-子流程-嵌套子流程

目录 定义图形标记XML内容使用示例视频讲解 定义 内嵌子流程又叫嵌入式子流程&#xff0c;它是一个可以包含其它活动、分支、事件&#xff0c;等的活动。我们通 常意义上说的子流程通常就是指的内嵌子流程&#xff0c;它表现为将一个流程&#xff08;子流程&#xff09;定义在…

【C语言初阶(20)】调试练习题

文章目录 前言实例1实例2 前言 在我们开始调试之前&#xff0c;应该有个明确的思路&#xff1b;程序是如何完成工作的、变量到达某个步骤时的值应该是什么、出现的问题大概会在什么位置。这些东西在调试之前都需要先确认下来&#xff0c;不然自己都不知道自己在调试个什么东西…

IT服务管理学习笔记<一>

### IT服务管理知识整理 ITSM 的核心思想是&#xff0c;IT 组织&#xff0c;不管它是企业内部的还是外部的&#xff0c;都是 IT 服务提供者&#xff0c;其 主要工作就是提供低成本、高质量的 IT 服务。 ITSM 的核心思想是&#xff0c;IT 组织&#xff0c;不管它是企业内部的还…

中国农村大学生学习了这个【React教程】迎娶导师女儿,出任CEO走上人生巅峰

注&#xff1a;最后有面试挑战&#xff0c;看看自己掌握了吗 文章目录 React创建一个简单的 JSX 元素创建一个复杂的 JSX 元素在 JSX 中添加注释渲染 HTML 元素为 DOM 树 &#x1f338;I could be bounded in a nutshell and count myself a king of infinite space. 特别鸣谢…

《数据同步-NIFI系列》Nifi配置DBCPConnectionPool连接SQL Server数据库

Nifi配置DBCPConnectionPool连接SQL Server数据库 一、新增DBCPConnectionPool 在配置中新增DBCPConnectionPool&#xff0c;然后配置数据库相关信息 二、配置DBCPConnectionPool 2.1 DBCPConnectionPool介绍 主要介绍以下五个必填参数 Database Connection URL&#xff1…

简历上的项目,需要这样描述才有亮点!

作者&#xff1a;小傅哥 博客&#xff1a;https://bugstack.cn 沉淀、分享、成长&#xff0c;让自己和他人都能有所收获&#xff01;&#x1f604; 一、前言&#xff1b;豆包不是干粮 每每准备面试&#xff0c;总有些小伙子甩出自己的豆包项目&#xff0c;不是Xxx管理系统&…

绝绝子,这所211无歧视!极其保护一志愿!专硕爆冷全部录取!

一、学校及专业介绍 大连海事大学&#xff08;Dalian Maritime University&#xff09;&#xff0c;简称海大&#xff0c;位于辽宁省大连市&#xff0c;是中华人民共和国交通运输部所属的全国重点大学&#xff0c;位列国家“双一流”、“211工程”重点建设高校。 1.1 招生情况…

HJ99 自守数+OR86N 返回小于N的质数个数

HJ99 自守数 自守数_牛客题霸_牛客网 (nowcoder.com) #include <iostream> #include<cmath> using namespace std; bool Ending_Same(int a) {int a_a a * a;if (a_a a)return true;int i 1;while (a_a ! 0 && a_a/ (int)pow(10, i)!0)//保证a*a有足够…

SBFI AM(Na+Indicator),129423-53-6,可用来预测纯化线粒体Na+梯

资料编辑|陕西新研博美生物科技有限公司小编MISSwu​ SBFI AM(NaIndicator)钠离子荧光探针 PART1----​Product structure&#xff1a; PART2----​Product specifications&#xff1a; 1.CAS No&#xff1a;129423-53-6 2.Molecular formula&#xff1a;C56H58N2O23 3.Molec…

算法:HJ27 查找兄弟单词

描述 定义一个单词的“兄弟单词”为&#xff1a;交换该单词字母顺序&#xff08;注&#xff1a;可以交换任意次&#xff09;&#xff0c;而不添加、删除、修改原有的字母就能生成的单词。 兄弟单词要求和原来的单词不同。例如&#xff1a; ab 和 ba 是兄弟单词。 ab 和 ab 则…

职业发展规划指南:如何成为成功的产品经理

导语&#xff1a;产品经理是当今互联网时代最炙手可热的职位之一。作为连接技术、商业和用户需求的桥梁&#xff0c;产品经理在公司中扮演着至关重要的角色。本文将为你提供一些关于产品经理职业发展的规划指南&#xff0c;帮助你在这个领域取得成功。 掌握核心技能&#xff1…

修复navicat 不可用

第一步&#xff1a;关闭Navicat 第二步&#xff1a;打开注册表编辑器&#xff0c;win R, 输入regedit 第三步&#xff1a; 在最上方搜索框输入HKEY_CURRENT_USER\Software\PremiumSoft\NavicatPremium 将Registration15XCS文件夹 和 Update文件夹删除 第四步&#xff1a; 在…

Jenkins工具系列 —— Jenkins 安装并启动

文章目录 安装涉及相关链接选择安装Jenkins版本安装JenkinsJenkins web页面启动 安装涉及相关链接 Jenkins官网&#xff1a; https://www.jenkins.io/zh/ Jenkins下载安装步骤&#xff1a; https://www.jenkins.io/zh/download/ 安装各种版本OpenJDK&#xff1a; https://blog…

netty3和netty4 的区别

netty3和netty4 的区别 目录概述需求&#xff1a; 设计思路实现思路分析1.区别 拓展实现性能参数测试&#xff1a; 参考资料和推荐阅读 Survive by day and develop by night. talk for import biz , show your perfect code,full busy&#xff0c;skip hardness,make a better…

SpringBoot项目中使用Lombok插件中Slf4j日志框架

前言&#xff1a;idea需要安装lombok插件&#xff0c;因为该插件中添加了Slf4j注解&#xff0c;可以将Slf4j翻译成 private static final org.slf4j.Logger logger LoggerFactory.getLogger(this.XXX.class); springboot本身就内置了slf4j日志框架&#xff0c;所以不需要单独…

Vue前端框架入门

文章目录 Vue快速入门Vue指令生命周期 Vue 经过一小段时间学习 我认为vue就是在原js上进行的一个加强 简化JS中的DOM操作 vue是分两个层的 一个叫做视图层(View)&#xff0c;你可以理解为展现出来的前端页面 一个叫数据模型层(Model),包含数据和一些数据的处理方法 MVVM就是实…