java后端学习

部署

vue项目部署

vue打包命令
renren-fast 修改配置
index-prod.js
修改为服务器地址
在这里插入图片描述

npm run build
    listen       80;
    server_name  localhost;

    #charset koi8-r;
    #access_log  /var/log/nginx/log/host.access.log  main;

    location / {
    #采用docker目录挂载,只需要在宿主机对应的目录放好vue打包文件
        root   /usr/share/nginx/html;
        index  index.html index.htm;
    }
     location /test {
        root   /usr/share/nginx/html;
        index  /test/index.html /test/index.htm;
    }

#vue与服务部署在同一台服务器,所以用localhost
        location /renren-fast {
            proxy_pass http://localhost:8080/renren-fast;
        }

参考博文:

如何进行vue项目的部署

feign

get请求传对象

	PageVO<User> getObject(@SpringQueryMap User user);

返回mybatisplus的分页数据,无法序列化

自己封装一个page

@Data
public class PageVO<T> implements Serializable {
	private static final long serialVersionUID = -5161145370999313156L;
	private List<T> records;
	private Long total;
	private Long size;
	private Long current;
}

java

java应用访问mysql失败

参考博文:

在这里插入代码片

解决java.sql.SQLException: null, message from server: "Host ‘XXX’ is not allowed to connect异常

启动jar包并指定配置文件

spring:
  profiles:
    active: dev
java -jar demo.jar --spring.profiles.active=pro 

参考博文:

java -jar 命令下指定boot的启动时加载的配置文件

序列化和反序列化

一个对象实现了序列化接口,他的集合也可序列化,因为集合也实现了序列化接口。
如果一个对象内部的属性也是一个集合,则他的泛型对象也需要实现序列化接口。
序列化前后版本号需要一致,否则会出现下面的错误

java.io.InvalidClassException: java基础.序列化.User; local class incompatible: stream classdesc serialVersionUID = 4680606320177667957, local class serialVersionUID = 1680606320177667957
  User rx = new User("rx", 1);
        User rx2 = new User("rx2", 2);
        User rx3 = new User("rx3", 3);
        ArrayList<User> users = new ArrayList<>();
        try (
                FileOutputStream fos = new FileOutputStream("object.out");
                ObjectOutputStream oos = new ObjectOutputStream(fos)
                ){
            users.add(rx);
            users.add(rx2);
            users.add(rx3);
            oos.writeObject(users);
        }catch (Exception e){
            e.printStackTrace();
        }
        try (
                FileInputStream fis = new FileInputStream("object.out");
                ObjectInputStream ois = new ObjectInputStream(fis)
                ){
            ArrayList<User> o = (ArrayList<User>)ois.readObject();
            System.err.println(o);
        }catch (Exception e){
            e.printStackTrace();
        }

集合

arraylist

参考博文:

ArrayList常用方法总结
ArrayList使用迭代器遍历删除元素(迭代器的具体实现)
ArrayList和HashMap的遍历选择删除,集合的迭代删除

treeset

排序:实现Comparable或者Comparator,后者比较灵活。
一般需要排序才使用treeset,否则使用hashset
参考博文:

Set集合之TreeSet集合
HashSet和TreeSet的使用场景

map转对象

 HashMap<String, Object> map = new HashMap<>();
 map.put("name","rx");
 map.put("userType",12);
 UserInfo userInfo1 = JSONObject.parseObject(JSONObject.toJSONString(map), UserInfo.class);
 System.err.println(userInfo1);

异常

try-catch-finally

1、三个代码块中都有return,最终返回的是finally
2、try或者catch中执行了return,finally再对return的结果做修改,不会影响返回结果。

jdk7以后自动关闭流的方式

try(
      FileInputStream fis = new FileInputStream("D:\\javaDemo\\test\\jjj");
      FileOutputStream fos = new FileOutputStream("D:\\javaDemo\\test\\kkk");
) {
	  byte[] bs = new byte[1024];
	  int len = 0;
	  while ((len = fis.read(bs)) != -1) {
	      fos.write(bs, 0, len);
	  }
}

接口

接口中不可含有抽象方法

Java中抽象类和接口中有构造方法吗?

流式处理

数组转化为流

Integer[] arr = {1, 2, 3, 4, 5};
Stream<Integer> stream7 = Stream.of(arr);

对象拷贝

参考博文:

对象属性拷贝方式

BeanUtils

@Test
    public void r2(){
        UserBindVO userBindVO = new UserBindVO();
        userBindVO.setIdCard("iddsd");
        userBindVO.setName("rx");
        userBindVO.setBankType("12");
        userBindVO.setBankNo("xsx");
        userBindVO.setMobile("43");
        UserBind userBind = new UserBind();
        BeanUtils.copyProperties(userBindVO, userBind);
        System.err.println(userBind);
    }

idea

自制idea插件

参考博文:

自制插件

idea插件

参考博客:

【idea】推荐一个idea翻译插件:Translation

idea引用本地jar包

在这里插入图片描述
导入库中的所有jar
在这里插入图片描述
也可以从这里添加单个jar包
在这里插入图片描述

idea启动多个实例

在这里插入图片描述

idea打jar包

在这里插入图片描述
选择主类
在这里插入图片描述
jar包输出位置
在这里插入图片描述
构建jar
在这里插入图片描述
运行jar

java -jar   xxx.jar
nohup java -jar xxx.jar &

使用此方法对springboot项目进行打包

如果之前用同样的方法打包过,需要删除文件
在这里插入图片描述
如果只勾选框出来的
在这里插入图片描述
就是打包不包含依赖的jar包,否则就是包含依赖的jar包
在这里插入图片描述
运行

java -cp maventest.jar rx.maventest.MaventestApplication

虽然可以运行,但总感觉有问题。暂时存疑。

存在多个主类时。
在这里插入图片描述
在这里插入图片描述

在这里插入图片描述
在这里插入图片描述
然后build
运行对应的主类
在这里插入图片描述

java -cp **.jar  主类的全类名

如果有多个主类的情况下,选择第一种打包方式,则用java -jar 运行,并且只会运行之前指定的主类。

maven

参考博文:

尚硅谷学习参考地址

maven搭建项目

参考博文:

使用idea创建一个Maven java Web项目

maven打包

微服务的pom配置
父工程

 <build>
        <plugins>
             <plugin>
                 <!--spring-boot-maven-plugin插件是将springboot的应用程序打包成fat jar的插件-->
                 <groupId>org.springframework.boot</groupId>
                 <artifactId>spring-boot-maven-plugin</artifactId>
             </plugin>
         </plugins>
</build>

不含有主方法类的模块

    <build>
        <plugins>
            <!--跳过父项目传递过来的 spring-boot-maven-plugin 的 repackage -->
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
                <version>2.3.7.RELEASE</version>
                <configuration>
                    <skip>true</skip>
                </configuration>
                <executions>
                    <execution>
                        <id>repackage</id>
                        <goals>
                            <goal>repackage</goal>
                        </goals>
                    </execution>
                </executions>
            </plugin>
            <!-- maven-shade-plugin 是为了打包其依赖的 lib -->
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-shade-plugin</artifactId>
                <executions>
                    <execution>
                        <configuration>
                            <!--不生成 dependency-reduced-pom.xml-->
                            <createDependencyReducedPom>false</createDependencyReducedPom>
                        </configuration>
                        <phase>package</phase>
                        <goals>
                            <goal>shade</goal>
                        </goals>
                    </execution>
                </executions>
            </plugin>
        </plugins>
    </build>

参考博文:

多 module Spring-Boot 项目 repackage 问题
解决spring-boot-maven-plugin:2.2.1.RELEASE:repackage failed: Unable to find main class
spring-boot-maven插件repackage(goal)的那些事
Maven生命周期和插件的那些事(2021版)

maven项目部署

nexus私服

下载地址

将windos版本解压。然后设置环境变量
在这里插入图片描述

在这里插入图片描述
启动并访问,默认8081

http://localhost:8081/

登入账号admin,
密码在

F:\Program Files\sonatype-work\nexus3\admin.password

访问需要验证
在这里插入图片描述
创建仓库
在这里插入图片描述
在这里插入图片描述
设置阿里云镜像仓库代理
在这里插入图片描述
点击public,将aliyun添加进分组
在这里插入图片描述

在这里插入图片描述
修改maven settings文件

<mirrors>
		<mirror>
			<id>nexus</id>
			<name>nexus Maven</name>
			<mirrorOf>*</mirrorOf>
			<url>http://localhost:8081/repository/maven-public/</url>
		</mirror>
</mirrors>

踩坑:mvn deploy 在命令行和idea右侧执行结果不同
原因:在命令行默认读取的是settings.xml文件,idea插件读取的是自己配置的xml
参考博文:

IDEA打包deploy梳理

maven命令

命令作用
mvn dependency:list显示项目依赖列表
mvn dependency:tree以树形结构查看工程依赖信息
mvn installjar包安装到本地仓库
mvn clean install -Dmaven.test.skip=true安装到本地仓库
mvn clean package spring-boot:repackage -Dmaven.test.skip=true打包

依赖作用域

compile:通常使用的第三方框架的 jar 包这样在项目实际运行时真正要用到的 jar 包都是以 compile 范围进行依赖的。比如 SSM 框架所需jar包。
test:测试过程中使用的 jar 包,以 test 范围依赖进来。比如 junit。
provided:在开发过程中需要用到的“服务器上的 jar 包”通常以 provided 范围依赖进来。比如 servlet-api、jsp-api。而这个范围的 jar 包之所以不参与部署、不放进 war 包,就是避免和服务器上已有的同类 jar 包产生冲突,同时减轻服务器的负担。说白了就是:“服务器上已经有了,你就别带啦!”

1、打成war包

直接将war包放到本地tomcat的webapps目录下面,然后启动tomcat。
访问:http://localhost:8080/test5/ (test5是war包名称)

maven clean执行失败,检查项目是不是正在运行。

Failed to execute goal org.apache.maven.plugins:maven-clean-plugin:2.5:clean (default-clean) on project maventest: Failed to clean project: Failed to delete C:\Users\Rx\Desktop\maventest\target\maventest-0.0.1-SNAPSHOT.jar

如果在idea中执行过java -jar 需要退出程序,重新进入idea。
经过实验,还必须出现这样的报错后,再退出进入,才会有用。

optional

只会被自己使用,不会发生依赖传递

exclusion

主动排除传递过来的依赖

idea maven插件爆红

在这里插入图片描述
原因是根据换了,本地maven仓库的地址,需要从新导入jar包,可以用webapp模板新建的maven工程。会用到这些插件,然后自动导入jar。

pom.xml

参考博文:

史上最全的 pom.xml 文件详解

settings.xml

参考博文:

Maven的settings.xml配置详解
Maven的仓库和settings.xml配置文件
Idea新建项目默认是JDK1.5解决办法
idea每次创建项目JDK版本都是1.5的解决方法

mybatis

mybatis在xml中遍历集合

<if test="eqpGroupQueryDTO.eqpIdList != null and eqpGroupQueryDTO.eqpIdList.size>0">
            and a.id not in
            <foreach collection="eqpGroupQueryDTO.eqpIdList" open="(" close=")" separator="," item="id">
                #{id}
            </foreach>
</if>

redisson

缓存一致性问题

  • 缓存一致性问题
    * 1、双写模式 写数据库之后,写缓存
    * 2、失效模式,改完数据库之后,删除缓存
    * 可以加读写锁
    * 经常修改不用放缓存,直接读数据库

单一实例+本地锁实现读redis缓存

//每个线程进来,先判断redis中数据是否存在。如果不存在,就会去查询数据库,并放入缓存。
//当这个线程释放锁以后,其他线程再次竞争锁,需要再次查看缓存中是否有数据。这样就可以实
//现只查询一次数据库。
public ProdObjProductEntity testRedis(QueryWrapper<ProdObjProductEntity> queryWrapper) {
		Object testRedis = redisTemplate.opsForValue().get("testRedis");
		if (testRedis == null) {
			synchronized (this) {
				System.err.println("读数据库");
				return getProdObjProductEntity(queryWrapper);
			}
		} else {
			System.err.println("查缓存");
			return (ProdObjProductEntity) testRedis;
		}
	}
private ProdObjProductEntity getProdObjProductEntity(QueryWrapper<ProdObjProductEntity> queryWrapper) {
		Object testRedis;
		testRedis = redisTemplate.opsForValue().get("testRedis");
		if (testRedis == null) {
			System.err.println("查库了");
			ProdObjProductEntity one = this.getOne(queryWrapper);
			redisTemplate.opsForValue().set("testRedis", one);
			return one;
		}
		System.err.println("查缓存");
		return (ProdObjProductEntity) testRedis;
	}

但是如果是多实例状态,就会查询多次数据库。

多实例+redisLock实现分布式锁读缓存

public ProdObjProductEntity testRedisWithRedisLock(QueryWrapper<ProdObjProductEntity> queryWrapper) {
//		System.err.println(redissonClient);
		Object testRedis = redisTemplate.opsForValue().get("testRedis");
		if (testRedis == null) {
			ProdObjProductEntity redisLock = getRedisLock(queryWrapper);
			return redisLock;
		} else {
			System.err.println("查缓存");
			return (ProdObjProductEntity) testRedis;
		}
	}
	/**
	 * 缓存一致性问题
	 * 1、双写模式 写数据库之后,写缓存
	 * 2、失效模式,改完数据库之后,删除缓存
	 * 可以加读写锁
	 * 经常修改不用放缓存,直接读数据库
	 *
	 * @param queryWrapper
	 * @return
	 */
	public ProdObjProductEntity getRedisLock(QueryWrapper<ProdObjProductEntity> queryWrapper) {
		RLock redisLock = redissonClient.getLock("redisLock");
		redisLock.lock();
		System.err.println("获取分布式锁成功");
		ProdObjProductEntity prodObjProductEntity;
		try {
			prodObjProductEntity = getProdObjProductEntity(queryWrapper);
		} finally {
			redisLock.unlock();
		}
		return prodObjProductEntity;
	}

过滤重复请求

实现功能:所有请求排队进入,并且一分钟内只有一个请求会被执行,其他会被跳过。
可用于实现接口幂等。

	@GetMapping("/testBladeLock")
	public String testBladeLock() {
//String baldelock = redisLockClient.lock("baldeLock", LockType.REENTRANT, 10, 10, TimeUnit.SECONDS, () -> {
//			return "success";
//		});
		RLock lock = redissonClient.getLock("my-lock");
//redisson 有看门狗会自动续期 并且可以自动释放锁 运行期间会自动续期30秒,如果服务挂了或者异常,就无法自动续
//期,所以不会发生死锁
//方法一、10秒后自动解锁 (存在问题:业务还没执行完毕,就给解锁了) 自动解锁时间一定要大于业务执行时间  不会自
//动续期
//		lock.lock();
//方法二、每隔10秒续期到30
//		lock.lock(10, TimeUnit.SECONDS);
		//方法三、最佳时间设置30秒 而不是采用自动续期
		//trylock 尝试加锁,等待一段时间后,就放弃,lock是一直等待
		//公平锁 有顺序的获取锁 先来后到 非公平锁 只要锁释放 会继续抢占
		try {
			//尝试5秒去获取锁,没有成功就放弃。
			boolean b = lock.tryLock(5, 30, TimeUnit.SECONDS);
			System.err.println("加锁成功" + Thread.currentThread().getId());
			if (b) {
//				String uuid = UUID.randomUUID().toString();
//该请求,在一分钟内只会执行一次
				Boolean lockFlag = redisTemplate.opsForValue().setIfAbsent("lock", "1", 60, TimeUnit.SECONDS);
				if (lockFlag) {
					System.out.println("执行业务" + Thread.currentThread().getId());
					//	Thread.sleep(5000);
				} else {
					System.err.println("跳过业务" + Thread.currentThread().getId());
				}
			} else {
				System.err.println("加锁失败" + Thread.currentThread().getId());
				return "hello world";
			}
		} catch (InterruptedException e) {
			e.printStackTrace();
		} finally {
			//假设解锁代码没有执行,会不会死锁 (不会死锁)
			if (lock.isLocked() && lock.isHeldByCurrentThread()) {
				System.err.println("解锁成功" + Thread.currentThread().getId());
				lock.unlock();
			}
		}
		return "hello";
	}

测试可重入锁

/**
	 * 测试可重入锁
	 */
	@GetMapping("/testReEntranceLock")
	@ApiOperationSupport(order = 1)
	@ApiOperation(value = "详情", notes = "传入prodobjproduct")
	public String testReEntranceLock() {
		RLock lock = redissonClient.getLock("my-lock");
		//redisson 有看门狗会自动续期 并且可以自动释放锁 运行期间会自动续期30秒,如果服务挂了或者异常,就无法自动续期,所以不会发生死锁
//		lock.lock();
		//10秒后自动解锁 (存在问题:业务还没执行完毕,就给解锁了) 自动解锁时间一定要大于业务执行时间  不会自动续期
		//每隔10秒续期到30
		lock.lock(10, TimeUnit.SECONDS);
		//最佳时间设置30秒 而不是采用自动续期
		//trylock 尝试加锁,等待一段时间后,就放弃,lock是一直等待
		//公平锁 有顺序的获取锁 先来后到 非公平锁 只要锁释放 会继续抢占
		try {
			System.err.println("加锁成功" + Thread.currentThread().getId());
			Thread.sleep(1000);
		} catch (InterruptedException e) {
			e.printStackTrace();
		} finally {
			//假设解锁代码没有执行,会不会死锁 (不会死锁)
			System.err.println("解锁成功" + Thread.currentThread().getId());
			lock.unlock();
		}
		return "hello";
	}

读写锁

//写锁是排它锁,保证读取到最新数据,写锁没有释放,读取就必须等待
	//写+读 等待写锁释放
	//读+写 写锁等待
	//写+写 阻塞
	//读+读 相当于无锁
	@GetMapping("/write")
	public String writeValue() {
		RReadWriteLock lock = redissonClient.getReadWriteLock("rw-lock");
		String s = "";
		RLock rLock = lock.writeLock();

		try {
			//改数据加写锁,读数据加读锁 保证读取的都是最新数据
			rLock.lock();
			System.err.println("加写锁");
			s = UUID.randomUUID().toString();
			Thread.sleep(30000);
			redisTemplate.opsForValue().set("writeValue", s);
		} catch (InterruptedException e) {
			e.printStackTrace();
		} finally {
			System.err.println("解写锁");
			rLock.unlock();
		}
		return s;
	}

@GetMapping("/read")
	public String readValue() {
		RReadWriteLock lock = redissonClient.getReadWriteLock("rw-lock");
		String s = "";
		RLock rLock = lock.readLock();

		try {
			rLock.lock();
			System.err.println("加读锁");
			Thread.sleep(30000);
			s = redisTemplate.opsForValue().get("writeValue");
		} catch (Exception e) {
			e.printStackTrace();
		} finally {
			System.err.println("解读锁");
			rLock.unlock();
		}
		return s;
	}

闭锁

	/**
	 * 闭锁
	 * 放假锁门 必须等待所有人走完了 才可以锁门
	 */
	@GetMapping("/lockDoor")
	public String lockDoor() throws InterruptedException {
		RCountDownLatch door = redissonClient.getCountDownLatch("door");
		door.trySetCount(5);
		//等待闭锁完成
		door.await();
		return "放假了";
	}

	@GetMapping("/gogo/{id}")
	public String gogo(@PathVariable("id") Long id) {
		RCountDownLatch door = redissonClient.getCountDownLatch("door");
		door.countDown();
		return id + "走了";
	}

信号量

	/**
	 * 车库停车
	 * 走一个进入一个
	 * 信号量可以用于分布式限流
	 * 先go再park
	 */
	@GetMapping("/park")
	public String park() {
		RSemaphore park = redissonClient.getSemaphore("park");
		//获取信号量 阻塞方法
		try {
			park.acquire();
//			park.tryAcquire() 不会阻塞等待 不行就算了
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
		return "ok";
	}


	/**
	 * 车库停车
	 * 走 释放车位
	 */
	@GetMapping("/go")
	public String go() {
		RSemaphore park = redissonClient.getSemaphore("park");
		//获取信号量 阻塞方法
		try {
			park.release();
		} catch (Exception e) {
			e.printStackTrace();
		}
		return "go";
	}

shell

新建和运行shell

新建test.sh

#!/bin/bash
echo "Hello World !"

执行
1、作为可执行程序

#! 是一个约定的标记,它告诉系统这个脚本需要什么解释器来执行,即使用哪一种 Shell。
chmod +x test.sh

2、作为解释器参数

/bin/sh test.sh
/bin/php test.php

变量定义和赋值

your_name="tom"
echo $your_name
your_name="alibaba"
echo $your_name

使用变量,建议${aaa}
字符串,单引号和双引号都可以使用

参数传递

echo "Shell 传递参数实例!";
echo "执行的文件名:$0";
echo "第一个参数为:$1";
echo "第二个参数为:$2";

shell文件包含

a.sh引用b.sh

#使用 . 号来引用test1.sh 文件
. ./test1.sh
# 或者使用以下包含文件代码
# source ./test1.sh
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Ranx3

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值