-Virbox代码加密

Virbox 文档

一、SDK

1.1注册 Virbox开发者账号

注册地址:https://developer.lm.virbox.com/reg.html

1.2申请转正(成为开发者)

1.3下载开发者工具盒

在【概览】页面-【工具资料】模块,点击【开发者工具盒】即可下载Virbox开发者工具盒

安装工具盒并登录

点击【下载SDK】,检测后【立即更新】

二、许可发布流程

2.1创建产品

2.2创建授权码模板

带红色星号的都是必填

2.3生成授权码(发布许可)

2.3.1发布许可

2.3.2填写

2.3.3生成完毕

三、软件加密(jar包加密)

3.1打开加壳工具

jar包放入新建的一个文件夹中

3.2登录开发锁,填API密码

API密码在

下拉即可看到

3.3拖入jar包文件夹,填写许可选项

填写java密码:

  • 密码如果不设置,会随机默认密码。
  • 建议设置一个密码,并牢记,后续更新jar包时,重新加密时填写此密码,则无需更换配置sjt库。

3.4消息提示选项

当程序被加密后,程序就与我们之前创建的许可进行关联,当用户在使用我们的加密的程序时如果触发了一些限制时,会以该界面上的消息进行显示

3.5完成保护

配置好信息后,选中项目,点击“保护选中项目”,进行加密

生成一个文件夹和加密配置文件

文件夹中:加密后的jar包和sjt_agent.jar文件

四、使用加密后的程序

4.1安装用户工具

运行加密后的软件是需要先运行Virbox用户工具

Virbox用户工具下载链接:https://lm.virbox.com/tools.html

windows环境

直接双击安装

Linux环境

  • rpm安装:rpm -ivh senseshield-2.5.0.60698-1.x86_64.rpm
  • deb安装:dpkg -i senseshield-2.5.0.60698-i386.deb
  • 服务启动查看:service senseshield status 或者 systemctl status senseshield

4.2绑定授权码

windows环境

打开Virbox 用户工具,点击【云/软锁】—【本地软锁】—【授权码在线激活】,会打开授权码激活页面,将生成的授权码输入,点击激活即可。

粘贴授权码并点击激活

Linux环境

1.联网环境下打开终端
1
2
//例:ssclt --online_bind_license_key --license_key 26W7-4ZTP-38YP-JRX1
ssclt --online_bind_license_key --license_key [授权码]

激活成功会有success的字样

2.使用ssclt --slock查看已绑定的软锁许可

4.3运行jar包

windows系统

1.把slm_runtime_java.dll文件复制或移动到jdk17的bin目录下

2.运行方式:运行 jar 包时指定 sjt 文件目录

  • 若 sjt_agent.jar 和 jar 包在同一目录,进入到jar包的当前目录下,直接执行

    命令:java -javaagent:sjt_agent.jar -jar ***.jar

  • 若 sjt_agent.jar 和 jar包 不在同一目录,需要指定文件的全目录。

    命令:java -javaagent:C:\Users\test\Desktop\sjt\sjt_agent.jar -jar ***.jar

Linux 系统

1.下列文件需要上传到服务器新建的目录

目录lib下的文件是libslm_runtime_java.so

2.解压jdk-17_linux-x64_bin.tar.gz文件

使用解压命令

1
tar -zxvf jdk-17_linux-x64_bin.tar.gz

或直接执行jieya.sh文件解压jdk

1
./jieya.sh

3.执行start.sh文件
1
./sstart.sh

文件内容如下:

1
2
3
4
5
6
export JAVA_HOME=./jdk-17.0.9
export CLASSPATH=.:${JAVA_HOME}/lib
export PATH=.:${JAVA_HOME}/bin:$PATH
export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:./lib
java -javaagent:sjt_agent.jar -jar udyk-2.1.jar

方式二:

或是直接在终端运行jiance.sh,此脚本会自动检测当前系统是否安装了宝塔面板、检测用户工具是否已安装、检测运行项目所需要的服务是否已经启动、检测服务全部启动后帮助用户激活授权码以及检测jdk是否已解压,一些就绪后,将会执行start.sh脚本启动项目。

服务器shell脚本运行成功一切正常的情况下

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
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
# 检查是否已经安装了宝塔面板
#系统类型 默认0 Ubuntu:1 Deepin:2 Centos:3
system_type=0

if ps aux | grep bt | grep -v grep > /dev/null ; then
echo "宝塔面板已安装"
else
echo "宝塔面板未安装,马上执行安装!"
# 检测是什么系统,安装宝塔面板
if [[ $(uname -s) == "Linux" ]]; then
if [[ -f /etc/lsb-release && $(grep DISTRIB_ID= /etc/lsb-release | cut -d= -f2) == "Ubuntu" ]]; then
echo "是Ubuntu,安装Ubuntu的宝塔面板"
system_type=1
#wget -O install.sh https://download.bt.cn/install/install-ubuntu_6.0.sh && sudo bash install.sh
elif [[ -f /etc/os-release && $(grep '^ID=' /etc/os-release | cut -d= -f2 | sed 's/"//g') == "deepin" ]]; then
echo "是Deepin,安装Deepin的宝塔面板"
system_type=2
#wget -O install.sh https://download.bt.cn/install/install-ubuntu_6.0.sh && sudo bash install.sh
elif [[ -f /etc/redhat-release && $(cat /etc/redhat-release | awk '{print $1}') == "CentOS" ]]; then
echo "是centos,安装Centos的宝塔面板"
#yum install -y wget && wget -O install.sh https://download.bt.cn/install/install_6.0.sh && sh install.sh
system_type=3
fi
fi
fi

# 检测是否安装了virbox用户工具
if ps aux | grep senseshield | grep -v grep > /dev/null ; then
echo "用户工具已安装"
else
echo "用户工具未安装"
if [[ $(uname -s) == "Linux" ]]; then
if [[ -f /etc/lsb-release && $(grep DISTRIB_ID= /etc/lsb-release | cut -d= -f2) == "Ubuntu" ]]; then
system_type=1
elif [[ -f /etc/os-release && $(grep '^ID=' /etc/os-release | cut -d= -f2 | sed 's/"//g') == "deepin" ]]; then
system_type=2
elif [[ -f /etc/redhat-release && $(cat /etc/redhat-release | awk '{print $1}') == "CentOS" ]]; then
system_type=3
fi
fi
fi

# 安装virbox用户工具
if [[ $system_type == "1" || $system_type == "2" ]]; then
echo "安装virbox用户工具---Ubuntu/Deepin"
#dpkg -i senseshield-2.5.0.60698-i386.deb
elif [[ $system_type == "3" ]]; then
echo "安装virbox用户工具---Centos"
#rpm -ivh senseshield-2.5.0.60698-1.x86_64.rpm
fi

# 检查服务是否启动
services=("nginx" "mysql" "redis" "senseshield")
started_services=0 # 记录已启动的服务数量
for service in "${services[@]}"
do
if pgrep "$service" >/dev/null
then
echo "$service 服务已经启动"
started_services=$((started_services+1))
else
echo "$service 服务未启动"
fi
done

if [[ $started_services -eq ${#services[@]} ]]; then
echo "依赖服务全部已启动"
# 服务全部启动后,进行用户工具的激活授权码操作
while ! [[ $license_key =~ ^[0-9A-Z]{4}-[0-9A-Z]{4}-[0-9A-Z]{4}-[0-9A-Z]{4}$ ]]; do
echo "请输入授权码(格式:XXXX-XXXX-XXXX-XXXX):"
# 读取用户输入,并校验
read license_key
if ! [[ $license_key =~ ^[0-9A-Z]{4}-[0-9A-Z]{4}-[0-9A-Z]{4}-[0-9A-Z]{4}$ ]]; then
echo "授权码格式不正确"
fi
done
echo "激活完毕,即将运行……"
echo "查看目录"
ls
if [ -d jdk-17.0.9 ]; then
echo "jdk-17.0.9 目录存在"
echo "运行jar包……"
./start.sh
else
echo "jdk-17.0.9 目录不存在"
echo "解压jdk……"
./jieya.sh
./start.sh
fi
fi

五、获取授权码中的数据区

5.1前提是在产品管理中创建产品的时候,填写上数据区的内容

5.2创建授权码模板时勾选上数据区的内容

5.3在代码中整理好示例

  • 此处的三个文件在

    【D:\Virbox\senseshield\sdk\API\Java\Sample\SlmRuntimeJava】目录下

  • 或者:此处也可以使用导入jar包的方式使用Sample示例

    jar包在【D:\Virbox\senseshield\sdk\API\Java\Sample\SlmRuntimeJava】目录下

    在pom.xml中定义

    1
    2
    3
    4
    5
    6
    7
    <dependency>
    <groupId>com.udeve</groupId>
    <artifactId>SlmRuntimeJava</artifactId>
    <scope>system</scope>
    <systemPath>${project.basedir}/src/main/resources/lib/SlmRuntimeJava.jar</systemPath>
    <version>1</version>
    </dependency>

5.4更改API密码和许可ID

5.5注释掉用不到的代码,防止报错

5.6把DLL文件复制一份到jdk的bin中

D:\Virbox\senseshield\sdk\API\Java\dll\x64下的slm_runtime_java.dll文件,挪到D:\Java\jdk-17\bin

5.7测试、运行代码

1
2
3
4
5
6
7
8
public static void main(String[] args) {
Sample.Virbox(7764);
JSONObject object = Sample.DataObject;
JSONObject userData = object.getJSONObject("userData");
JSONObject pubData = object.getJSONObject("pubData");
System.out.println(userData);
System.out.println(pubData);
}

5.8输出

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
slm_get_developer_id success !
developerId = 0300000000000009
slm_init success!
slm_login success!
slm_keep_alive success!
slm_find_license success !
license_desc = [{"developer_id":"0300000000000009","lm":"pub","account_name":"SC1895000000003","user_guid":"71fbab6f28854962a52816bcb3a6e5b6","host_name":"DESKTOP-HO61AG6","ip":"","port":0,"type":"slock"}]
slm_check_module failure : 0x13000037! License module not exist.
slm_get_info failure : 0x00000010! Unsupported operation.
slm_user_data_getsize success! pmemSize = 103
slm_user_data_read success!
readBuff = CUSTOM_COPYRIGHT:no;HOUSE_MAX_COUNT:10;OPEN_API:no;POST_MAX_COUNT:1;TOUR_MAX_COUNT:1;USER_MAX_COUNT:100
slm_user_data_write before size = 0
slm_pub_data_getsize success!
pmem_size = 13
slm_pub_data_read success!
slm_pub_data_read readBuf = name:zhangsan
slm_logout success!
slm_cleanup success!
test over ......
{"OPEN_API":"no","CUSTOM_COPYRIGHT":"no","TOUR_MAX_COUNT":"1","HOUSE_MAX_COUNT":"10","USER_MAX_COUNT":"100","POST_MAX_COUNT":"1"}
{"name":"zhangsan"}

Process finished with exit code 0

下图分别是数据区的只读区公开区的数据内容

2023-10-24-Git学习

Git学习

常见的版本控制工具

我们学习的东西,一定是当下最流行的!

主流的版本控制器有如下这些:

  • Git
  • SVN(Subversion)
  • CVS(Concurrent Versions System)
  • VSS(Micorosoft Visual SourceSafe)
  • TFS(Team Foundation Server)
  • Visual Studio Online

版本控制产品非常的多(Perforce、Rational ClearCase、RCS(GNU Revision Control System)、Serena Dimention、SVK、BitKeeper、Monotone、Bazaar、Mercurial、SourceGear Vault),现在影响力最大且使用最广泛的是Git与SVN

版本控制分类

1、本地版本控制

记录文件每次的更新,可以对每个版本做一个快照,或是记录补丁文件,适合个人用,如RCS。

图片

2、集中版本控制 SVN

所有的版本数据都保存在服务器上,协同开发者从服务器上同步更新或上传自己的修改

图片

所有的版本数据都存在服务器上,用户的本地只有自己以前所同步的版本,如果不连网的话,用户就看不到历史版本,也无法切换版本验证问题,或在不同分支工作。而且,所有数据都保存在单一的服务器上,有很大的风险这个服务器会损坏,这样就会丢失所有的数据,当然可以定期备份。代表产品:SVN、CVS、VSS

3、分布式版本控制 Git

每个人都拥有全部的代码!安全隐患!

所有版本信息仓库全部同步到本地的每个用户,这样就可以在本地查看所有版本历史,可以离线在本地提交,只需在连网时push到相应的服务器或其他用户那里。由于每个用户那里保存的都是所有的版本数据,只要有一个用户的设备没有问题就可以恢复所有的数据,但这增加了本地存储空间的占用。

不会因为服务器损坏或者网络问题,造成不能工作的情况!

图片

Git和SVN最主要区别

svn是集中式版本控制系统,版本库是集中放在中央服务器的,而工作的时候,用的都是自己的电脑,所以要从中央服务器得到最新的版本,然后工作,需要把自己做完的活推送到中央服务器。集中式版本控制系统是必须联网才能工作,对网络带宽要求较高。

Git是分布式本本控制系统,没有中央服务器,每个人的电脑就是一个完整的版本库,工作的时候不需要联网了,因为版本都在自己的电脑上,协同的方法是这样的:比如说自己在电脑上改了A,其他人也在电脑上改了A,这时候,你们两之间只需要把各自的修改推送给对方,就可以互相看到对方的修改了,Git可以直接看到更新了哪些代码和文件!

Git是目前世界上最先进的分布式版本控制系统

Git历史

同生活中的许多伟大事物一样,Git 诞生于一个极富纷争大举创新的年代。

Linux 内核开源项目有着为数众广的参与者。绝大多数的 Linux 内核维护工作都花在了提交补丁和保存归档的繁琐事务上(1991-2002年间)。到 2002 年,整个项目组开始启用一个专有的分布式版本控制系统 BitKeeper 来管理和维护代码。

Linux社区中存在很多的大佬!破解研究 BitKeeper !

到了 2005 年,开发 BitKeeper 的商业公司同 Linux 内核开源社区的合作关系结束,他们收回了 Linux 内核社区免费使用 BitKeeper 的权力。这就迫使 Linux 开源社区(特别是 Linux 的缔造者 Linus Torvalds)基于使用 BitKeeper 时的经验教训,开发出自己的版本系统。(2周左右!) 也就是后来的 Git!

Git是目前世界上最先进的分布式版本控制系统。

Git是免费、开源的,最初Git是为辅助 Linux 内核开发的,来替代 BitKeeper!图片

Linux和Git之父李纳斯·托沃兹(Linus Benedic Torvalds)1969、芬兰

环境配置:

淘宝镜像安装Git : https://npm.taobao.org/mirrors/git-for-windows/v2.25.1.windows.1/

图片

Git Bash:Unix与Linux风格的命令行,使用最多,推荐最多

Git CMD:Windows风格的命令行

Git GUI:图形界面的Git,不建议初学者使用,尽量先熟悉常用命令

基本的Linux命令学习

  1. cd:改变目录
  2. cd .. :回退到上一个目录,直接cd 进入默认目录
  3. pwd:显示当前坐在的目录路径
  4. ls(ll):都是列出当前目录中的所有文件,只不过ll列出的内容详细
  5. touch:新建一个文件 touch index.js 新建index.js文件
  6. rm:删除一个文件,rm index.js 就会把index.js文件删除
  7. mkdir:新建一个目录,就是新建一个文件夹
  8. rm -r:删除一个文件夹,rm -r src 删除src目录
  9. mv :移动文件,mv index.html src;index.html是我们要移动的文件,src是目标文件夹,当然,这样写必定是在同一目录下
  10. reset:重新初始化终端/清屏
  11. clear :清屏
  12. history :查看命令历史
  13. help:帮助
  14. exit:退出
  15. #:注释

Git配置

查看配置 git config -l

系统配置git config --system --list

本地配置(用户配置)git config --global --list

Git相关的配置文件

\Git\etc\gitconfig:Git安装目录下的gitconfig –system级

1620956099413

C:\Users\飞驰的苏弋: 只适用于当前登录用户的配置 –global

1620956352338

==设置用户名和邮箱(用户标识,必要)==

当年装Git后首先要做的事情是设置你的用户名称和e-mail地址。这是非常重要的,因为每次Git提交都会使用该信息。它被永远的嵌入到了你的提交中:

1
2
git config --global user.name  "suyi"   #名称
git config --global user.email "990784805@qq.com"

Git基本理论(核心)

工作区域

Git本地有三个工作区域:中作目录(Working Directory)、暂存区(Stage/Index)、资源库(Repository或Git Directory)。如果在加上远程的git仓库(Remote Directory)就可以分为四个工作区域。文件在这四个区域之间的转换关系如下:

1620956950822

  • Workspace:工作区,就是你平时存放项目代码的地方
  • Index/Stage:暂存区,用于临时存放你的改动,事实上它只是一个文件,保存即将提交到文件列表信息
  • Repository:仓库区(或本地仓库),就是安全存放数据的位置,这里面有你提交到所有版本的数据。其中HEAD指向最新放入仓库的版本。
  • Remote:远程仓库,托管代码的服务器,可以简单的认为是你项目组中的一台电脑用于远程数据交换

本地的三个区域确切的说应该是git仓库中HEAD指向的版本:

1620957184415

  • Directory:使用Git管理的一个目录,也就是一个仓库,包含我们的工作空间和Git的管理空间。
  • Workspace:需要通过Git进行版本控制的目录和文件,这些目录和文件组成了工作空间。
  • .git:存放Git管理信息的目录,初始化仓库的时候自动创建。
  • Index/Stage:暂存区,或者叫待提交更新区,在提交进入repo之前,我们可以把所有的更新放在暂存区。
  • Local Repo:本地仓库,一个存放在本地的版本库;HEAD会只是当前的开发分支(branch)。
  • Stash:隐藏,是一个工作状态保存栈,用于保存/恢复Workspace中的临时状态。

工作流程

git的工作流程一般是这样的:

  1. 在工作目录中添加、修改文件;
  2. 将需要进行版本管理的文件放入暂存区;
  3. 将暂存区域的文件提交到git仓库。

因此,git管理的文件有三种状态:已修改(modified),已暂存(staged),已提交(committed)

1620957820224

Git项目搭建

创建工作目录与常用指令

工作目录(WorkSpace)一般就是你希望Git帮助你管理的文件夹,可以是你项目的目录,也可以是一个空目录,建议不要有中文。

日常使用只要记住下图6个命令:图片

本地仓库搭建

创建本地仓库的方法有两种,一种是创建全新的仓库,另一种是克隆远程仓库。

  1. 创建全新的仓库,需要用Git管理的项目的根目录执行。

    1
    2
    #在当前目录新建一个Git代码库
    git init
  2. 执行后可以看到,仅仅在项目目录多出了一个.git目录,关于本版等的信息都在这个目录里面。

克隆远程仓库

  1. 另一种方式是克隆远程目录,由于是将远程服务器上的仓库完全镜像一份至本地!

    1
    2
    #克隆一个项目和它的整个代码历史(版本信息)
    git clone [url] #https://gitee.com/kuangstudy/openclass.git
  2. 去gitee或者github上克隆一个测试!

git文件操作

文件的四种状态

版本控制就是对文件的版本控制,要对文件进行修改、提交等操作,首先要知道文件当前在什么状态,不然可能会提交了现在还不想提交的文件,或者要提交的文件没提交上。

  • Untracked: 未跟踪, 此文件在文件夹中, 但并没有加入到git库, 不参与版本控制. 通过git add 状态变为Staged.
  • Unmodify: 文件已经入库, 未修改, 即版本库中的文件快照内容与文件夹中完全一致. 这种类型的文件有两种去处, 如果它被修改, 而变为Modified. 如果使用git rm移出版本库, 则成为Untracked文件
  • Modified: 文件已修改, 仅仅是修改, 并没有进行其他的操作. 这个文件也有两个去处, 通过git add可进入暂存staged状态, 使用git checkout 则丢弃修改过, 返回到unmodify状态, 这个git checkout即从库中取出文件, 覆盖当前修改 !
  • Staged: 暂存状态. 执行git commit则将修改同步到库中, 这时库中的文件和本地文件又变为一致, 文件为Unmodify状态. 执行git reset HEAD filename取消暂存, 文件状态为Modified

查看文件状态

上面说文件有4种状态,通过如下命令可以查看到文件的状态:

1
2
3
4
5
6
7
8
9
#查看指定文件状态
git status [filename]

#查看所有文件状态
git status

#git add. 添加所有文件到暂存区
#git commit -m "消息内容" 提交暂存区中的内容到本地仓库 -m 提交信息

忽略文件

有些时候我们不想把某些文件纳入版本控制中,比如数据库文件,临时文件,设计文件等

在主目录下建立”.gitignore“文件,此文件有如下规则:

  1. 忽略文件中的空行或以井号(#)开始的行将会被忽略。
  2. 可以使用Linux通配符。例如:星号(*)代表任意多个字符,问号(?)代表一个字符,方括号([abc])代表可选字符范围,大括号({string1,string2,…})代表可选的字符串等。
  3. 如果名称的最前面有一个感叹号(!),表示例外规则,将不被忽略。
  4. 如果名称的最前面是一个路径分隔符(/),表示要忽略的文件在此目录下,而子目录中的文件不忽略。
  5. 如果名称的最后面是一个路径分隔符(/),表示要忽略的是此目录下该名称的子目录,而非文件(默认文件或目录都忽略)。
1
2
3
4
5
*.txt      #虎烈所有  .txt结尾的文件,这样的话上传就不会被选中
!lib.txt #但lib.txt除外
/temp/ #仅忽略项目根目录下的TODO文件,不包括其他目录temp
build/ #忽略build/目录下的所有文件
doc/*.txt #会忽略doc/notes.txt 但不包括doc/server/arch.txt

idea .gitignore文件配置

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
*.class

*.log

*.lock



#Package File

*.jar

*.war

*.ear



# idea

.idea/

*.iml



*.velocity.log*

### STS ###
.apt_generated
.factorypath
.springBeans

### IntelliJ

*.iml
*.ipr
*.iws
.idea
.classpath
.project
.settings/
bin/

*.log
tmp/

#rebel
*rebel.xml*

使用码云

github 是有墙的,比较慢,在国内的话,我们一般使用 gitee ,公司中有时候会搭建自己的gitlab服务器

这个其实可以作为大家未来找工作的一个重要信息!

  1. 注册登录码云,完善个人信息 图片

  2. 设置本机绑定SSH公钥,实现免密码登录!(免密码登录,这一步挺重要的,码云是远程仓库,我们是平时工作在本地仓库!)

    1
    2
    3
    # 进入 C:\Users\飞驰的苏弋\.ssh 目录
    # 生成公钥
    ssh-keygen

    图片

  3. 将公钥信息public key 添加到码云账户中即可! 图片

  4. 使用码云创建一个自己的仓库! 图片许可证:开源是否可以随意转载,开源但是不能商业使用,不能转载,…  限制!

    图片克隆到本地! 图片

IDEA中集成Git

  1. 新建项目,绑定git。 图片注意观察idea中的变化 图片

  2. 修改文件,使用IDEA操作git。

    • 添加到暂存区
    • commit 提交
    • push到远程仓库
  3. 提交测试 图片

    这些都是单个人的操作!

    学习的方式最重要!学会学习!我上课的更多时候都是在教大家去学习一种理念和思想(学习方式)

    有道无术、术尚可求。有术无道、止于术!

    真正的教学,授人以渔!

说明:Git分支

分支在GIT中相对较难,分支就是科幻电影里面的平行宇宙,如果两个平行宇宙互不干扰,那对现在的你也没啥影响。不过,在某个时间点,两个平行宇宙合并了,我们就需要处理一些问题了!

图片

图片

git分支中常用指令:

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
#列出所有本地分支
git branch

# 列出所有远程分支
git branch -r

# 新建一个分支,但依然停留在当前分支
git branch [branch-name]

# 新建一个分支,并切换到该分支
git checkout -b [branch]

# 合并指定分支到当前分支
$ git merge [branch]

# 删除分支
$ git branch -d [branch-name]

# 删除远程分支
$ git push origin --delete [branch-name]
$ git branch -dr [remote/branch]

#切换远程分支
$ git checkout -b suyi origin/suyi

IDEA中操作

图片

如果同一个文件在合并分支时都被修改了则会引起冲突:解决的办法是我们可以修改冲突文件后重新提交!选择要保留他的代码还是你的代码!

master主分支应该非常稳定,用来发布新版本,一般情况下不允许在上面工作,工作一般情况下在新建的dev分支上工作,工作完后,比如上要发布,或者说dev分支代码稳定后可以合并到主分支master上来。

Jwt的鉴权登录-拦截器-注册拦截器

一、实现大致流程

  • 在浏览器发起请求来执行登录操作,此时会访问登录的接口,如果访问的不是登录接口,为了安全,使其跳转到登录页面.如果登录成功之后,我们需要生成一个jwt令牌,将生成的 jwt令牌返回给前端。

  • 前端拿到jwt令牌之后,会将jwt令牌存储起来。在后续的每一次请求中都会将jwt令牌携带到服务端。

  • 服务端统一拦截请求之后,先来判断一下这次请求有没有把令牌带过来,如果没有带过来,直接拒绝访问,如果带过来了,还要校验一下令牌是否是有效。如果有效,就直接放行进行请求的处理。

二、JWT令牌

1.JWT是什么?

​ JWT (全称:Json Web Token)是一个开放标准(RFC 7519),它定义了一种简洁的、自包含的方式,用于作为 JSON 对象在各方之间安全地传输信息。该信息可以被验证和信任,因为它是数字签名的。

简洁:是指jwt就是一个简单的字符串。可以在请求参数或者是请求头当中直接传递。 自包含:指的是jwt令牌,看似是一个随机的字符串,但是我们是可以根据自身的需求在jwt令牌中存储自定义的数据内容。如:可以直接在jwt令牌中存储用户的相关信息。

简单点说就是一种认证机制,让后台知道该请求是来自于受信的客户端。JWT 主要用于用户登录鉴权

2.JWT令牌的组成

JWT的组成: (JWT令牌由三个部分组成,三个部分之间使用英文的点来分割)

  • 第一部分:Header(头), 记录令牌类型、签名算法等。 例如:{“alg”:”HS256”,”type”:”JWT”}

  • 第二部分:Payload(有效载荷),携带一些自定义信息、默认信息等。 例如:{“id”:”1”,”username”:”Tom”}

  • 第三部分:Signature(签名),防止Token被篡改、确保安全性。将header、payload,并加入指定秘钥,通过指定签名算法计算而来。

签名的目的就是为了防jwt令牌被篡改,而正是因为jwt令牌最后一个部分数字签名的存在,所以整个jwt 令牌是非常安全可靠的。一旦jwt令牌当中任何一个部分、任何一个字符被篡改了,整个令牌在校验的时候都会失败,所以它是非常安全可靠的。

img

3,JWT令牌在登录认证的应用

  1. 在浏览器发起请求来执行登录操作,此时会访问登录的接口,如果登录成功之后,我们需要生成一个jwt令牌,将生成的 jwt令牌返回给前端。

  2. 前端拿到jwt令牌之后,会将jwt令牌存储起来。在后续的每一次请求中都会将jwt令牌携带到服务端。

  3. 服务端统一拦截请求之后,先来判断一下这次请求有没有把令牌带过来,如果没有带过来,直接拒绝访问,如果带过来了,还要校验一下令牌是否是有效。如果有效,就直接放行进行请求的处理。

4,JWT令牌鉴权登录实现步骤

1,引入JWT依赖
1
2
3
4
5
6
<!-- JWT依赖-->
<dependency>
<groupId>io.jsonwebtoken</groupId>
<artifactId>jjwt</artifactId>
<version>0.9.1</version>
</dependency>
2,创建JWT工具类
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
 

public class JwtUtils {

private static String signKey = "xxx";
private static Long expire = 43200000L;

/**
* 生成JWT令牌
* @param claims JWT第二部分负载 payload 中存储的内容
* @return
*/
public static String generateJwt(Map<String, Object> claims){
String jwt = Jwts.builder()
.addClaims(claims)
.signWith(SignatureAlgorithm.HS256, signKey)
.setExpiration(new Date(System.currentTimeMillis() + expire))
.compact();
return jwt;
}

/**
* 解析JWT令牌
* @param jwt JWT令牌
* @return JWT第二部分负载 payload 中存储的内容
*/
public static Claims parseJWT(String jwt){
Claims claims = Jwts.parser()
.setSigningKey(signKey)
.parseClaimsJws(jwt)
.getBody();
return claims;
}
}
3,三层架构实现登录成功,生成JWT令牌并返回

controller层

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
/**
* 登录控制层
*
*/
@RestController
@Slf4j
@RequestMapping("/user")
public class UserController {
@Autowired
private UserService userService;

/**
* 登录
* @param user
* @return
*/
@PostMapping("/login")
public Result login(@RequestBody User user){
try {
log.info("登录{}",user);
String jwt = userService.login(user);
return Result.success(true,"登录成功!!",jwt);
} catch (Exception e) {
e.printStackTrace();
return Result.error(false,"登录失败!!");
}
}
}

Service层

接口

1
2
3
4
5
6
public interface UserService {
/**
* 用户登录
*/
String login(User user);
}

实现类

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
@Service
@Slf4j
public class UserServiceImpl implements UserService {
@Autowired
private UserMapper userMapper;


/**
* 用户登录
*/
@Override
public String login(User user) {
if(user == null || user.getUsername() == null || "".equals(user.getUsername())
|| user.getPassword() == null || "".equals(user.getPassword())){
throw new RuntimeException("用户不存在!!");
}
//根据用户查询用户的信息
User dbUser = userMapper.findByUsername(user.getUsername());
//判断密码是否正确
if (!user.getPassword().equals(dbUser.getPassword())){
throw new RuntimeException("用户名或密码错误!!");
}
//生成jwt令牌并返回
HashMap<String, Object> claims = new HashMap<>();
claims.put("id",dbUser.getId());
claims.put("username",dbUser.getUsername());
String jwt = JwtUtils.generateJwt(claims);
return jwt;
}
}

Mapper层

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
public interface UserService {
/**
* 用户登录
*/
String login(User user);
}

==========xml===============
<!--登录:根据用户名称查询用户信息-->
<select id="findByUsername" resultType="xxxxxxx">
select id,birthday,gender,username,password,
remark,station,telephone
from t_user
where username = #{username};
</select>

三、拦截器Interceptor

1,什么是拦截器?

​ 拦截器的主要是:基于Java的反射机制,属于**面向切面编程(AOP)**的一种运用,就是在Service或者一个方法前调用一个方法,或者在方法后调用一个方法,甚至在抛出异常的时候做业务逻辑的操作。

​ 拦截器的作用类似于Servlet 中的Filter(过滤器),都可以用于对处理器进行预处理和后处理。在Spring MVC 与Spring Boot 中使用拦截器一般是实现HandlerInterceptor 接口。

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

2,拦截器Interceptor鉴权登录实现步骤

1,定义拦截器
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
@Component
@Slf4j
public class LoginCheckInterceptor implements HandlerInterceptor{
//目标资源方法执行前执行。 返回true:放行 返回false:不放行
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
//1,先获取请求头
String token = request.getHeader("token");
response.setContentType("application/json;charset = UTF-8");
ObjectMapper mapper = new ObjectMapper();
//2,判断请求头是否存在
if (token == null || "".equals(token)){
//请求头不存在或者请求头为空
log.info("token不存在");
Result error = Result.error(false, "NOT_LOGIN");
String result = mapper.writeValueAsString(error);
response.getWriter().write(result);
return false;
}
//3,请求头不正确
try {
Claims claims = JwtUtils.parseJWT(token);
} catch (Exception e) {
log.info("请求头不正确!!");
Result error = Result.error(false, "NOT_LOGIN");
String result = mapper.writeValueAsString(error);
response.getWriter().write(result);
return false;
}
return true;
}

//==========下面与登录无关,不用写==============

//目标资源方法执行后执行
@Override
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
System.out.println("postHandle ... ");
}

//视图渲染完毕后执行,最后执行
@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
System.out.println("afterCompletion .... ");
}
}

注意:

  • preHandle方法:目标资源方法执行前执行。 返回true:放行 返回false:不放行
  • postHandle方法:目标资源方法执行后执行
  • afterCompletion方法:视图渲染完毕后执行,最后执行
2,注册配置拦截器
1
2
3
4
5
6
7
8
9
10
11
12
13
@Configuration
public class WebConfig implements WebMvcConfigurer {
@Autowired
private LoginCheckInterceptor loginCheckInterceptor;

@Override
public void addInterceptors(InterceptorRegistry registry) {
//定义拦截对象
registry.addInterceptor(loginCheckInterceptor)
.addPathPatterns("/**")
.excludePathPatterns("/user/login");
}
}

WebMvcConfigurer

WebMvcConfigurer接口中的核心方法之一addInterceptors(InterceptorRegistry registry)方法表示添加拦截器。主要用于进行用户登录状态的拦截,日志的拦截等。

  1. addInterceptor:需要一个实现HandlerInterceptor接口的拦截器实例
  2. addPathPatterns:用于设置拦截器的过滤路径规则;addPathPatterns(“/**”)对所有请求都拦截
  3. excludePathPatterns:用于设置不需要拦截的过滤规则,静态资源啥的

Linux系统部署SpringBoot项目

Linux系统部署SpringBoot项目

服务器环境准备 准备jdk,Nginx,MySQL

宝塔安装

Centos安装命令:

1
yum install -y wget && wget -O install.sh http://download.bt.cn/install/install_6.0.sh && sh install.sh
  1. 使用宝塔安装tomcat8(tomcat8会自带jdk8的环境)
  2. 安装Nginx(待会配置域名)
  3. 安装MySQL(服务使用线上数据库,当然你在打jar包之前就要配置好数据库了)

运行jar包

  1. 将jar包上传到服务器上(哪里都行,你能找到就好)
  2. 使用命令云jar包
    使用项目中默认的端口号
1
2
3
java -jar springboot-Linux-0.0.1-SNAPSHOT.jar --server.port=8080 >temp.txt &
#持续在Linux服务器上运行jar包
nohup java -jar springboot-Linux-0.0.1-SNAPSHOT.jar --server.port=8080 >temp.txt &

查看运行日志

1
cat temp.txt

如何关闭服务?

  1. 查看进程号
1
ps -ef|grep java
  1. 杀死进程
1
kill -s 9  104373

配置域名 (war包)

  1. 腾讯云或阿里云申请域名,解析域名,甚至域名备案;

  2. 腾讯云或阿里云端口号:8080 80 3306 22 21 等确认开放,并与宝塔面板端口开放保持一致
    1620899165288

    1620899216236

  3. 打开宝塔的tomcat的配置文件,配置项目路径: ==不必改端口号为80==

    1
    2
    3
    4
    <Host autoDeploy="true" name="haojiacheng.cn" unpackWARs="true" xmlNamespaceAware="false" xmlValidation="false">
    <Context crossContext="true" docBase="/www/server/tomcat/webapps/zhjc" path="" reloadable="true" />
    <Context docBase="/temp/images" path="/pic" />
    </Host>
  4. 点击,网站——–》添加站点——–》

    1. 有域名写域名,没域名写服务器外网IP
    2. 备注,FTP等看个人需求
    3. 根目录稍后设置
      1620897911106
  5. 添加完成后,测试在浏览器URL中直接输入服务器IP或域名,看是否显示站点创建成功。若成功,则去设置里改网站目录: 为自己的项目目录
    1620898097875

==404 not found nginx怎么解决方法==

或==网页的静态资源无法访问==

打开宝塔面板== =》网站== =》站点设置====》配置文件

添加或修改如下代码:

1
2
3
4
5
6
7
8
9
location ~ .*\.(gif|jpg|jpeg|bmp|png|ico|txt|js|css)$
{
#expires 12h;
proxy_pass http://haojiacheng.cn:8080;
}
location ~ .*\.(js|css)?$
{
proxy_pass http://haojiacheng.cn:8080;
}

注意:

  1. 使用thymeleaf摸版引擎在服务器上面出现的一种报错

    1
    2
    3
    spring:
    thymeleaf:
    prefix: classpath:/templates/
  2. 宝塔账号

1
2
3
4
外网面板地址: http://82.156.186.10:8888/612181c6
内网面板地址: http://10.0.8.8:8888/612181c6
username: suyi
password: Hjc17691324608

Linux操作数据库

腾讯云与宝塔面板都开启==3306==端口

宝塔面板给服务器安装MySQL

使用Xshell7 连接服务器,进入MySQL

mysql -u root -p

123456

use mysql

select host,user from user;

1620721330832

给与root最高权限,并且不限制访问主机ip,赋予密码123456

GRANT ALL PRIVILEGES ON *.* TO root@"%" IDENTIFIED BY "123456";

接下来直接在本地连接MySQL

1620721399535

Linux系统下的java代码===》文件上传下载

在Linux根目录下创建temp>images

1620729042127

并且给与temp和images这两个文件夹最高权限 否则java上传文件放不进来

1620729076601

Linux下的目录是File file=new File("/temp/images/"+newname+sux);

windows下的目录是: File file=new File("C:\\temp\\images\\"+newname+sux);

SVN学习

SVN学习

svn基本操作:

  • 检出:checkout
  • 新增:add
  • 提交:commit
  • 更新:update
  • 历史记录

下载

  •  TortoiseSVN
  • 汉化

an

tortoisesvn

Checkout检出代码

  1. 在SVNBucket的项目详情-源码页面-复制SVN地址
  2. 在你需要保存代码的地方右键选择SVN Chekout...
  3. 填写SVN地址,填写保存目录,输入SVNBucket网站登录用户名密码。
  4. 点击确定就能同步代码到本地了。

Update更新代码

右键 SVN Update 更新代码,这样就能把其他人提交的代码同步到自己电脑上了

SVN

Commit提交代码

提交代码也很简单,右键SVN Commit...,填入提交描述,就可以把本地提交的代码提交到服务器了。 在提交代码前我们应该update下代码,这是个好习惯,可以避免覆盖别人的代码和代码冲突。

svn

撤销和恢复

  • 撤销本地修改
  • 撤销已提交内容
  • 恢复到指定版本

本地:

svn

已提交

svn

恢复到指定版本

右键==》TortoiseSVN==》显示日志

  • 选择恢复到此版本 ==或==
  • 恢复此版本做出的修改

忽略

右键==》TortoiseSVN==》增加到忽略列表

取消忽略

右键==》TortoiseSVN==》从忽略列表删除

冲突

什么情况容易发生冲突?

  • 多个人修改了同个文件的同一行
  • 无法进行合并的二进制文件

怎么避免冲突

  • 经常update同步他人代码
  • 二进制文件不要多个人同时操作

冲突了怎么办

更新时发生冲突,可以选择

  • 使用“他们的”文本块解决冲突
  • 使用“我的”解决有冲突的文件
  • 编辑冲突,选择好时,右键==》使用此文本块

什么时候需要开分支?

  • 隔离线上版本和开发版本
  • 大功能开发,不想影响到其他人,自己独立开个分支去开发

SVN经典目录结构

  • trunk
  • branches
  • tags

SpringBoot的application常用配置

server配置

1
2
3
4
5
6
7
8
9
10
11
12
#1.配置tomcat访问端口
server:
port: 7778
#2.配置http://localhost:7778/aa/bb.html这个访问地址的意思
servlet:
context-path: /aa
#3.Session设置存活时间是30分钟
session-timeout: 30
#4.tomcat启动的最大线程数,即同时处理的任务个数,默认值为200
tomcat.max-threads: 0
#5.Tomcat在解析参数的时候没有使用正确的编码格式(UTF-8)去解码
tomcat.uri-encoding: UTF-8

spring配置

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
spring:
application:
#1.服务名称信息
name: mimi
#2.配置启动banner的编码和文字
banner:
charset: UTF-8
location: classpath:banner.txt
#3.spring下的配置数据库
datasource:
#1.配置数据库连接池(Druid,),HikariCP 是默认的
type: com.alibaba.druid.pool.DruidDataSource
#2.数据库的地址
url: jdbc:mysql://localhost:3306/testDB?characterEncoding=UTF-8&serverTimezone=UTC
#3.配置数据库驱动,jdbc
driver-class-name: com.mysql.cj.jdbc.Driver
#4.配置数据库连接的账号
username: root
#5.配置数据库连接的密码
password: 123456
#4.(spring:mvc下的)关于springmvc的设置
mvc:
#1.静态资源的过滤规则(在静态资源目录下,只有以/resources/开头的才能显示,不然不能显示)
static-path-pattern: /resources/**
#5.(spring:resources下的)设置静态资源的路径(默认的是classpath:/static,classpath:/public,classpath:/resources,classpath:/META-INF/resource)
resources:
static-locations: ["classpath:/static/", "classpath:/public/","classpath:/mapper/"]
#6.thymeleaf的模板配置
thymeleaf:
prefix: classpath:/templates
mode: HTML
cache: false
encoding: UTF-8
#新版本不支持content-type: text/html,故新写法
servlet:
content-type: text/html

mybatis配置

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
# mybatis的配置
mybatis:
#1.配置mapper文件放在resource下的mapper中
mapper-locations: classpath:/mapper/*.xml
#2.配置实体扫描,多个package用逗号或者分号分隔
type-aliases-package: com.example.demo.entity
#3.配置mybatis日志打印(这个生效后下面logging中的打印失效)
configuration:
log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
#4.配置mybatis配置文件
location: classpath:mybatis/mybatis-config.xml
#打印等级(com.example.demo.dao包下的日志会打印),不是mybatis子配置
logging:
level:
com.example.demo.dao: debug

SpringDataJpa学习笔记

SpringDataJpa学习笔记

一、xml配置方法

1、sql脚本

1
2
3
4
5
6
7
8
9
10
11
12
create DATABASE if not exists springdata_jpa
DEFAULT CHARACTER set utf8;

use springdata_jpa;

create table customer(
id int auto_increment PRIMARY KEY,
cust_name VARCHAR(50) DEFAULT '',
cust_address VARCHAR(100) DEFAULT ''
);
insert into customer(cust_name,cust_address)VALUES('张三','陕西省西安市长安区滦镇街道');
select * from customer;

2、导入pom依赖

父项目

1
2
3
4
5
6
7
8
9
10
11
12
<!--统一管理springdata子项目的版本-->
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.data</groupId>
<artifactId>spring-data-bom</artifactId>
<version>2021.1.0</version>
<scope>import</scope>
<type>pom</type>
</dependency>
</dependencies>
</dependencyManagement>

子模块

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
<dependencies>
<dependency>
<groupId>org.springframework.data</groupId>
<artifactId>spring-data-jpa</artifactId>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-entitymanager</artifactId>
<version>5.4.32.Final</version>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.47</version>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid</artifactId>
<version>1.1.16</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-test</artifactId>
<version>5.3.4</version>
<scope>test</scope>
</dependency>
</dependencies>

3、编写实体类pojo

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
56
57
58
59
60
61
62
package com.hjc.pojo;


import javax.persistence.*;

@Entity
@Table(name = "customer")
public class Customer {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(name = "id")
private Long custId;//客户Id

@Column(name = "cust_name")
private String custName;//客户名称

@Column(name = "cust_address")
private String custAddress;//客户地址

@Override
public String toString() {
return "Customer{" +
"custId=" + custId +
", custName='" + custName + '\'' +
", custAddress='" + custAddress + '\'' +
'}';
}

public Long getCustId() {
return custId;
}

public void setCustId(Long custId) {
this.custId = custId;
}

public String getCustName() {
return custName;
}

public void setCustName(String custName) {
this.custName = custName;
}

public String getCustAddress() {
return custAddress;
}

public void setCustAddress(String custAddress) {
this.custAddress = custAddress;
}

public Customer(Long custId, String custName, String custAddress) {
this.custId = custId;
this.custName = custName;
this.custAddress = custAddress;
}

public Customer() {
}
}

4、dao层(repositories)

CustomerRepository.java

1
2
3
4
5
6
7
8
package com.hjc.repositories;

import com.hjc.pojo.Customer;
import org.springframework.data.repository.CrudRepository;

public interface CustomerRepository extends CrudRepository<Customer,Long> {
}

5、spring配置文件

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
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:jpa="http://www.springframework.org/schema/data/jpa"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx.xsd
http://www.springframework.org/schema/data/jpa
https://www.springframework.org/schema/data/jpa/spring-jpa.xsd">
<!--用于整合jpa @EnableJpaRepositories-->
<jpa:repositories base-package="com.hjc.repositories"
entity-manager-factory-ref="entityManagerFactory"
transaction-manager-ref="jpaTransactionManager"/>
<!--entityManagerFactory-->
<bean name="entityManagerFactory" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
<property name="jpaVendorAdapter">
<bean class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter">
<property name="generateDdl" value="true"></property>
<property name="showSql" value="true"></property>
</bean>
</property>
<!--设置实体类的包-->
<property name="packagesToScan" value="com.hjc.pojo"></property>
<!--设置数据源 ref导入-->
<property name="dataSource" ref="dataSource"></property>
</bean>
<!--德鲁伊数据源-->
<bean class="com.alibaba.druid.pool.DruidDataSource" name="dataSource">
<property name="driverClassName" value="com.mysql.jdbc.Driver"/>
<property name="url" value="jdbc:mysql://localhost:3306/springdata_jpa?useUnicode=true&amp;characterEncoding=utf8&amp;zeroDateTimeBehavior=convertToNull&amp;useSSL=true&amp;serverTimezone=GMT%2B8"/>
<property name="username" value="root"/>
<property name="password" value="123456"/>
</bean>
<!--声明式事务-->
<bean name="jpaTransactionManager" class="org.springframework.orm.jpa.JpaTransactionManager">
<property name="entityManagerFactory" ref="entityManagerFactory"/>
</bean>
<!--注解驱动-->
<tx:annotation-driven transaction-manager="jpaTransactionManager"/>

</beans>

6、测试CRUD

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
56
57
58
59
60
61
62
63
package com.hjc;

import com.hjc.config.SpringDataJPAConfig;
import com.hjc.pojo.Customer;
import com.hjc.repositories.CustomerRepository;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;

import java.util.Optional;

@ContextConfiguration("classpath:spring.xml")
//@ContextConfiguration(classes = SpringDataJPAConfig.class)
@RunWith(SpringJUnit4ClassRunner.class)
public class springdatajpatest {

@Autowired
CustomerRepository customerRepository;


//查
@Test
public void mytest(){
Optional<Customer> byId = customerRepository.findById(1L);
System.out.println(byId.get());
}

//增
@Test
public void save(){
Customer customer = new Customer();
customer.setCustName("王五");
customer.setCustAddress("kjahsdkanklsjdas");
Customer save = customerRepository.save(customer);
System.out.println(save);
}

//改
@Test
public void update(){
Customer customer = new Customer();
customer.setCustId(2L);
customer.setCustName("李四");
customer.setCustAddress("北京市海定区update");
Customer save = customerRepository.save(customer);
System.out.println(save);
}

@Test
public void findAll(){
Iterable<Customer> all = customerRepository.findAll();
System.out.println(all);
}

//删
@Test
public void delete(){
customerRepository.deleteById(3L);
}

}

二、javaConfig方式

同上至第四步

4、Java配置文件

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
package com.hjc.config;

import com.alibaba.druid.pool.DruidDataSource;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.jpa.repository.config.EnableJpaRepositories;
import org.springframework.orm.jpa.JpaTransactionManager;
import org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean;
import org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter;
import org.springframework.transaction.PlatformTransactionManager;
import org.springframework.transaction.annotation.EnableTransactionManagement;

import javax.persistence.EntityManagerFactory;
import javax.sql.DataSource;

@Configuration
@EnableJpaRepositories(basePackages = "com.hjc.repositories")
@EnableTransactionManagement
public class SpringDataJPAConfig {

@Bean
public DataSource dataSource(){
DruidDataSource dataSource = new DruidDataSource();
dataSource.setDriverClassName("com.mysql.jdbc.Driver");
dataSource.setUrl("jdbc:mysql://localhost:3306/springdata_jpa?useUnicode=true&amp;characterEncoding=utf8&amp;zeroDateTimeBehavior=convertToNull&amp;useSSL=true&amp;serverTimezone=GMT%2B8");
dataSource.setUsername("root");
dataSource.setPassword("123456");

return dataSource;
}

/**
* 方法名必须是entityManagerFactory()
* @return
*/
@Bean
public LocalContainerEntityManagerFactoryBean entityManagerFactory(){
HibernateJpaVendorAdapter vendorAdapter = new HibernateJpaVendorAdapter();
vendorAdapter.setGenerateDdl(true);
vendorAdapter.setShowSql(true);
LocalContainerEntityManagerFactoryBean factoryBean = new LocalContainerEntityManagerFactoryBean();
factoryBean.setJpaVendorAdapter(vendorAdapter);
factoryBean.setPackagesToScan("com.hjc.pojo");
factoryBean.setDataSource(dataSource());
return factoryBean;
}

@Bean
public PlatformTransactionManager transactionManager(EntityManagerFactory entityManagerFactory){
JpaTransactionManager txManager = new JpaTransactionManager();
txManager.setEntityManagerFactory(entityManagerFactory);
return txManager;
}
}

5、测试

代码不变,把类上的@ContextConfiguration("classpath:spring.xml")

改成@ContextConfiguration(classes = SpringDataJPAConfig.class)

即可

三、项目结构截图:

1695644170139

四、需要注意的问题,也是我出现了bug的地方

在Javaconfig配置方式中

方法名:entityManagerFactory()不能改变

方法名必须是entityManagerFactory()

Thymeleaf实战指南

Thymeleaf实战指南

Thymeleaf是一种用于在Web应用中渲染动态内容的模板引擎。它提供了丰富的语法和功能,使开发人员能够轻松地在HTML模板中插入动态数据和逻辑处理。我们实训中用到的一些常用语法和示例写法给大家总结下:

Thymeleaf与Spring Boot集成步骤:

步骤1:在pom.xml中添加Thymeleaf和Spring Boot的依赖:

1
2
3
4
5
6
7
<dependencies>
<!-- Spring Boot Starter Thymeleaf -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>
</dependencies>

步骤2:配置Thymeleaf相关属性,如模板前缀、后缀等。在application.properties或application.yml中添加如下配置:

1
2
3
4
5
# Thymeleaf Configuration
spring.thymeleaf.prefix=classpath:/templates/
spring.thymeleaf.suffix=.html
spring.thymeleaf.mode=HTML
spring.thymeleaf.cache=false

步骤3:创建Thymeleaf模板文件。在src/main/resources/templates/目录下创建HTML模板文件。

步骤4:创建Controller类,处理请求并返回Thymeleaf模板。

1
2
3
4
5
6
7
8
9
@Controller
public class MyController {

@GetMapping("/")
public String home(Model model) {
model.addAttribute("message", "Hello Thymeleaf!");
return "index"; // 返回对应的Thymeleaf模板文件名
}
}

步骤5:在Thymeleaf模板中使用Thymeleaf的语法来渲染动态内容。

1
2
3
4
5
6
7
8
9
<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<head>
<title>Thymeleaf Example</title>
</head>
<body>
<h1 th:text="${message}"></h1>
</body>
</html>

Thymeleaf的常用语法

  1. 输出变量值:

    1
    <p th:text="${variable}">Default value</p>

    这会将变量${variable}的值输出到<p>标签中。

  2. 条件判断:

    1
    2
    <p th:if="${condition}">Condition is true</p>
    <p th:unless="${condition}">Condition is false</p>

    ${condition}为真时,第一个<p>标签将显示;当${condition}为假时,第二个<p>标签将显示。

  3. 循环迭代:

    1
    2
    3
    <ul>
    <li th:each="item : ${items}" th:text="${item}">Item</li>
    </ul>

    这会遍历${items}列表,并为每个元素创建一个<li>标签。

  4. 表单处理:

    1
    2
    3
    4
    <form th:action="@{/save}" method="post">
    <input type="text" name="name" />
    <button type="submit">Submit</button>
    </form>

    这是一个简单的表单,将数据提交到/save路径。服务端的代码:

后端代码,使用Spring MVC和Thymeleaf来处理表单提交:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
@Controller
public class MyController {

@PostMapping("/save")
public String saveForm(@RequestParam("name") String name) {
// 处理表单提交的逻辑
// 在这里可以对表单数据进行处理,如保存到数据库或进行其他操作
System.out.println("Received name: " + name);

// 返回重定向或渲染的视图
return "redirect:/success";
}

@GetMapping("/success")
public String showSuccessPage() {
// 显示提交成功页面
return "success";
}

}
  1. URL链接生成:

    1
    <a th:href="@{/users/{id}(id=${userId})}">User Details</a>

    这会生成一个链接,其中${userId}是动态的路径参数。

  2. 模板片段(Fragment):

    模板片段是一部分可以在多个页面中重用的HTML代码块。你可以将这些代码块提取出来,然后在不同的页面中引用它们。示例:

    1
    2
    3
    4
    5
    6
    7
    <!-- 定义模板片段 -->
    <div th:fragment="header">
    <h1>Welcome to My Website</h1>
    </div>

    <!-- 引用模板片段 -->
    <div th:replace="fragments/header :: header"></div>

    在以上示例中,header模板片段定义了一个标题,然后可以在其他页面中通过th:replace指令引用它。

  3. 国际化支持(Internationalization):

    Thymeleaf提供了简便的方式来处理国际化文本,以便在不同的语言环境下显示不同的内容。示例:

    1
    2
    <!-- 使用国际化文本 -->
    <h2 th:text="#{welcome.message}">Welcome</h2>

    在以上示例中,#{welcome.message}表示从国际化资源文件中获取名为welcome.message的文本,并将其显示在页面上。

  4. 片段缓存(Fragment Caching):

    片段缓存允许你缓存特定的HTML代码块,以提高页面的渲染性能。示例:

    1
    2
    3
    4
    <!-- 缓存模板片段 -->
    <div th:fragment="header" th:cacheable="true">
    <h1>Welcome to My Website</h1>
    </div>

    在以上示例中,通过将th:cacheable属性设置为true,可以将header模板片段进行缓存,以便在后续请求中直接使用缓存的结果,提高页面的响应速度。

Vue中 Runtime + Compiler 和 Runtime-only 两种模式含义和区别

一、问题描述

在使用 vue-cli 脚手架构建项目时,会遇到一个构建选项 Vue build,有两个选择,Runtime + Compiler 和 Runtime-only ,如图所示

Runtime + Compiler: recommended for most users

运行程序+编译器:推荐给大多数用户

Runtime-only: about 6KB lighter min+gzip, but templates (or any Vue-specific HTML) are ONLY allowed in .vue files - render functions are required elsewhere

仅运行程序: 比上面那种模式轻大约 6KB,但是 template (或任何特定于vue的html)只允许在.vue文件中使用——其他地方用需要 render 函数

二、两种模式的区别

runtime-only 比 runtime-compiler 轻 6kb,代码量更少
runtime-only 运行更快,性能更好
runtime-only 其实只能识别render函数,不能识别template,.vue 文件中的template也是被 vue-template-compiler 翻译成了render函数,所以只能在.vue里写 template
有关vue中的render函数可以看这篇博客:vue中的render函数

三、解释

两种模式生成的 脚手架 即(代码模板)主要区别在 main.js 中,其它基本上是一样的:

我们再看一张图:

runtime + compiler 中 Vue 的运行过程

对于 runtime-compiler 来说,它的代码运行过程是:template -> ast -> render -> virtual dom -> UI

首先将vue中的template模板进行解析解析成abstract syntax tree (ast)抽象语法树
将抽象语法树在编译成render函数
将render函数再翻译成virtual dom(虚拟dom)
将虚拟dom显示在浏览器上
runtime-only 中 Vue 的运行过程

对于 runtime-only来说,它是从 render -> virtual dom -> UI

可以看出它省略了从template -> ast -> render的过程
所以runtime-only比runtime-compiler更快,代码量更少
runtime-only 模式中不是没有写 template ,只是把 template 放在了.vue 的文件中了,并有一个叫 vue-template-compiler 的开发依赖时将.vue文件中的 template 解析成 render 函数。 因为是开发依赖,不在最后生产中,所以最后生产出来的运行的代码没有template

四、总结

如果在之后的开发中,你依然使用template,就需要选择 Runtime + Compiler

如果你之后的开发中,使用的是.vue文件夹开发,那么可以选择 Runtime-only

原文链接:https://blog.csdn.net/weixin_43974265/article/details/112743656