1. 项目概述与环境准备
最近在国产化替代的浪潮下,不少项目都开始要求在基于Linux内核的国产操作系统上进行部署,比如银河麒麟、中标麒麟等。我手头一个典型的Vue+SpringBoot前后端分离项目,就遇到了从熟悉的Windows开发环境迁移到麒麟系统的挑战。整个过程踩了不少坑,也总结了一套相对通用的部署流程。如果你也正面临类似的任务,无论是为了适配国产化环境,还是单纯想在Linux服务器上部署你的全栈应用,这篇从实战中摸爬滚打出来的经验,应该能帮你省下不少折腾的时间。
简单来说,我们要做的就是把一个前端用Vue构建、后端用SpringBoot打包的Jar包项目,完整地部署到一台全新的麒麟系统服务器上。这不仅仅是运行一个命令那么简单,它涉及到系统环境配置、依赖安装、服务部署、网络打通以及后期的维护监控。整个过程可以拆解为几个核心环节:首先是服务器基础环境的搭建,包括Java运行环境、Node.js环境(用于构建前端)以及Web服务器(如Nginx)的安装;其次是前后端代码的构建与部署;最后是配置反向代理,让前后端能够协同工作,并通过系统服务实现开机自启。下面,我就结合具体的操作步骤和踩过的坑,带你走一遍完整的流程。
1.1 核心需求与前置条件解析
在开始动手之前,我们必须明确目标和梳理清楚手头的资源。这个部署方案的核心目标是:在麒麟系统上,建立一个稳定、可维护的生产环境,能够运行SpringBoot后端服务,并对外提供由Nginx代理的Vue前端页面。
首先,你需要一台安装了麒麟系统的服务器。无论是物理机还是虚拟机,确保你能通过SSH远程连接,并拥有root权限或具备sudo权限的普通用户账号。这是所有操作的基础。其次,明确你的项目代码状态。通常,我们假设你已经在开发机上完成了前后端的编码和本地测试,并且拥有:
- 一个可用的SpringBoot项目,能够通过Maven或Gradle打包生成一个独立的、可执行的Jar文件(例如
your-app-0.0.1-SNAPSHOT.jar)。 - 一个Vue项目,能够通过
npm run build或yarn build成功生成静态资源文件,通常位于dist目录下。
服务器的网络环境也需要考虑。你需要知道服务器的IP地址,并确保防火墙规则允许访问你计划使用的端口,例如后端的8080端口和前端的80或443端口。如果服务器在局域网内,还需要考虑域名解析或直接使用IP访问。
注意:强烈建议在正式部署前,在本地或测试环境完整走通构建和部署流程。避免直接在生产服务器上边查边做,容易引入错误和安全隐患。
1.2 服务器基础环境检查与配置
拿到一台新的麒麟服务器,第一步不是急着装软件,而是先做一次全面的“体检”。不同的麒麟系统版本(如V10、V4)可能基于不同的Linux发行版(如CentOS、Ubuntu),其包管理器和默认配置会有差异。通过命令cat /etc/os-release或uname -a可以查看系统详细信息。
1. 系统更新与基础工具安装为了保证软件源的稳定性和安装过程的顺利,首先更新系统包管理器并安装一些后续必备的工具。
# 假设是基于CentOS的麒麟系统(使用yum) sudo yum update -y sudo yum install -y vim wget curl net-tools lsof # 如果是基于Ubuntu/Debian的麒麟系统(使用apt) sudo apt update && sudo apt upgrade -y sudo apt install -y vim wget curl net-tools lsof安装vim是为了方便编辑配置文件,wget和curl用于下载文件,net-tools和lsof则是网络诊断和查看端口占用情况的利器。
2. 防火墙与SELinux配置麒麟系统默认可能开启防火墙和SELinux,这对于新手来说是两大“拦路虎”。为了简化初期部署,我们可以先进行宽松配置,待应用完全跑通后再细化安全策略。
- 防火墙:开放必要端口。
# 查看防火墙状态(firewalld) sudo systemctl status firewalld # 开放端口(例如80, 443, 8080) sudo firewall-cmd --zone=public --add-port=80/tcp --permanent sudo firewall-cmd --zone=public --add-port=443/tcp --permanent sudo firewall-cmd --zone=public --add-port=8080/tcp --permanent sudo firewall-cmd --reload # 如果使用iptables,命令有所不同,需根据系统调整。 - SELinux:生产环境建议在充分了解后配置,测试环境可临时设置为宽容模式。
我的经验是,在部署阶段如果遇到莫名其妙的“权限不足”错误,而文件和目录权限明明正确,多半是SELinux在作祟。暂时设为宽容模式可以快速定位问题。# 查看SELinux状态 getenforce # 临时设置为宽容模式(重启失效) sudo setenforce 0 # 永久禁用(需编辑 /etc/selinux/config,将SELINUX=enforcing改为SELINUX=disabled,然后重启) # 注意:永久修改有安全风险,请谨慎评估。
2. 核心依赖安装:JDK、Node.js与Nginx
基础环境就绪后,就要安装运行我们项目的三大支柱:Java环境、Node.js环境和Web服务器。
2.1 安装Java运行环境(JDK)
SpringBoot项目需要JRE或JDK来运行。生产环境推荐安装稳定的JDK版本(如JDK 8、11或17)。你可以选择安装系统源里的OpenJDK,也可以从Oracle官网下载。
方案一:使用yum/apt安装OpenJDK(推荐,方便管理)
# 基于CentOS的麒麟系统 sudo yum install -y java-11-openjdk-devel # 以JDK11为例 # 基于Ubuntu的麒麟系统 sudo apt install -y openjdk-11-jdk安装后,通过java -version和javac -version验证是否安装成功。
方案二:手动下载安装Oracle JDK如果项目对特定版本的Oracle JDK有要求,可以手动下载。
- 访问Oracle官网或可信镜像站下载对应版本的
.tar.gz包(如jdk-11.0.xx_linux-x64_bin.tar.gz)。 - 解压到指定目录,例如
/usr/local/java/。sudo tar -zxvf jdk-11.0.xx_linux-x64_bin.tar.gz -C /usr/local/java/ - 配置环境变量。编辑
/etc/profile文件,在末尾添加:export JAVA_HOME=/usr/local/java/jdk-11.0.xx export PATH=$JAVA_HOME/bin:$PATH - 使配置生效:
source /etc/profile,然后再次验证java -version。
实操心得:生产环境强烈建议使用OpenJDK,它完全开源且与麒麟系统的兼容性通常更好。手动安装JDK时,务必注意解压路径和环境变量配置的准确性,一个字符错误都可能导致命令找不到。
2.2 安装Node.js与npm/yarn
Node.js主要用于构建Vue前端项目。我们需要安装Node.js以及其包管理器npm。同样,可以选择系统源安装或使用NodeSource仓库安装较新版本。
方案一:使用NodeSource仓库安装(推荐,版本新)
# 以安装Node.js 18.x为例 curl -fsSL https://rpm.nodesource.com/setup_18.x | sudo bash - # 对于基于CentOS的系统 # 对于基于Ubuntu的系统,命令类似,请参考NodeSource官网 sudo yum install -y nodejs # 安装完成后,验证 node -v npm -v方案二:使用系统包管理器安装版本可能较旧,但胜在稳定。
# 基于CentOS的麒麟系统 sudo yum install -y nodejs npm # 基于Ubuntu的麒麟系统 sudo apt install -y nodejs npm如果系统源的Node.js版本过低(Vue CLI可能需要Node.js 12+),建议采用方案一。
安装yarn(可选但推荐)yarn是另一个高效的包管理器,有时比npm更快、更稳定。
npm install -g yarn yarn --version2.3 安装与配置Nginx
Nginx将扮演两个角色:一是作为静态文件服务器,托管Vue构建出的dist目录;二是作为反向代理服务器,将前端对后端API的请求转发到SpringBoot应用。
安装Nginx
# 基于CentOS的麒麟系统 sudo yum install -y nginx # 基于Ubuntu的麒麟系统 sudo apt install -y nginx关键目录说明:
- 配置文件目录:
/etc/nginx/。主配置文件是nginx.conf,通常我们会在/etc/nginx/conf.d/目录下为每个站点创建独立的.conf文件。 - 默认网站根目录:
/usr/share/nginx/html。但我们通常会为项目创建专属目录。 - 日志目录:
/var/log/nginx/。
安装后,启动Nginx并设置开机自启:
sudo systemctl start nginx sudo systemctl enable nginx此时,在浏览器访问服务器IP,应该能看到Nginx的欢迎页面,这证明Nginx安装成功。
3. 前后端项目构建与部署
环境准备妥当,现在开始处理我们的项目代码。通常,我们不会在服务器上直接进行git clone和构建(除非是自动化CI/CD流水线),更常见的做法是在本地或构建服务器上完成构建,然后将产物上传到生产服务器。
3.1 后端SpringBoot项目打包与传输
1. 本地打包在你的开发机上,确保项目依赖都已下载,然后使用Maven或Gradle打包。以Maven为例,在项目根目录执行:
mvn clean package -DskipTests这会在target目录下生成一个可执行的Jar文件,比如myapp-0.0.1-SNAPSHOT.jar。这个Jar包已经内嵌了Tomcat服务器和所有依赖,是“一站式”的。
2. 上传Jar包至服务器使用scp命令或SFTP工具(如FileZilla)将Jar包上传到服务器的一个专用目录。我习惯在/home下为应用创建一个目录。
# 在服务器上创建目录 sudo mkdir -p /home/myapp/backend # 假设Jar包在本地,使用scp上传(从本地机器执行) scp target/myapp-0.0.1-SNAPSHOT.jar user@your_server_ip:/home/myapp/backend/3. 运行SpringBoot应用在服务器上,进入该目录,可以直接用java -jar命令运行。但为了更好的管理(如后台运行、日志收集、开机自启),我们通常将其配置为系统服务。
简单测试运行:
cd /home/myapp/backend java -jar myapp-0.0.1-SNAPSHOT.jar & # 使用 & 让它在后台运行。但这样管理不便,且终端关闭后进程可能终止。使用curl localhost:8080或查看日志,确认后端服务是否成功启动并在监听8080端口。
3.2 前端Vue项目构建与部署
1. 本地构建在Vue项目根目录下,安装依赖并执行构建命令。构建会压缩和优化代码,生成用于生产的静态文件。
# 安装依赖(如果已有node_modules可跳过) npm install # 或 yarn install # 执行构建 npm run build # 或 yarn build构建成功后,项目根目录下会生成一个dist文件夹,里面就是所有静态资源(HTML, JS, CSS, 图片等)。
2. 上传静态资源至服务器同样,将整个dist目录上传到服务器为前端准备的目录。
# 在服务器上创建目录 sudo mkdir -p /home/myapp/frontend # 上传dist目录内容(从本地机器执行) scp -r dist/* user@your_server_ip:/home/myapp/frontend/3. 配置Nginx托管前端现在,我们需要告诉Nginx,当用户访问网站时,去/home/myapp/frontend这个目录找文件。 在/etc/nginx/conf.d/目录下创建一个新的配置文件,例如myapp_frontend.conf。
sudo vim /etc/nginx/conf.d/myapp_frontend.conf写入以下配置:
server { listen 80; server_name your_domain.com; # 如果没有域名,可以用服务器IP或 localhost # 前端静态文件目录 root /home/myapp/frontend; index index.html index.htm; # 防止路由在刷新时出现404 location / { try_files $uri $uri/ /index.html; } # 配置静态资源缓存 location ~* \.(js|css|png|jpg|jpeg|gif|ico|svg)$ { expires 1y; add_header Cache-Control "public, immutable"; } # 可选:配置后端API代理(也可以单独配置,见下一节) # location /api/ { # proxy_pass http://localhost:8080; # proxy_set_header Host $host; # proxy_set_header X-Real-IP $remote_addr; # proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; # proxy_set_header X-Forwarded-Proto $scheme; # } }这个配置做了几件事:监听80端口;设置网站根目录;配置了Vue Router的history模式支持(try_files指令);为静态资源设置了长期缓存以提高性能。
保存并退出后,测试Nginx配置语法是否正确:
sudo nginx -t如果显示syntax is ok和test is successful,就可以重载Nginx配置使其生效:
sudo systemctl reload nginx现在,访问服务器的IP地址(或你配置的域名),应该能看到Vue前端页面了。但此时页面里的API请求(如果前端配置了/api这样的基础路径)会直接发向前端服务器(即Nginx的80端口),而后端实际运行在8080端口,所以会报404错误。接下来就需要配置反向代理来打通前后端。
4. 配置Nginx反向代理与系统服务
这是将前后端连接起来的关键一步,也是配置的精华所在。
4.1 配置Nginx反向代理后端API
我们不建议在前端代码里直接写后端服务器的IP和端口,而是通过Nginx统一转发。这样更安全、更灵活。修改上面创建的myapp_frontend.conf,或者单独创建一个API代理配置。
我更倾向于将前后端代理配置放在同一个server块里,管理起来方便。更新后的myapp_frontend.conf完整示例如下:
server { listen 80; server_name your_domain.com; # 改为你的域名或IP # 前端静态资源 root /home/myapp/frontend; index index.html index.htm; # 前端路由支持 location / { try_files $uri $uri/ /index.html; } # 后端API代理 - 假设你的前端请求以 /api 开头 location /api/ { # 代理到后端SpringBoot应用 proxy_pass http://127.0.0.1:8080/; # 注意结尾的斜杠,它会影响URL重写 proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header X-Forwarded-Proto $scheme; # 可选:增加超时设置,应对长耗时请求 proxy_connect_timeout 60s; proxy_send_timeout 60s; proxy_read_timeout 60s; } # 可选:代理WebSocket(如果应用用到) # location /ws/ { # proxy_pass http://127.0.0.1:8080; # proxy_http_version 1.1; # proxy_set_header Upgrade $http_upgrade; # proxy_set_header Connection "upgrade"; # } # 静态资源缓存 location ~* \.(js|css|png|jpg|jpeg|gif|ico|svg)$ { expires 1y; add_header Cache-Control "public, immutable"; } }关键点解析:
location /api/: 这个配置块匹配所有以/api开头的请求。proxy_pass http://127.0.0.1:8080/;: 将这些请求转发到本机8080端口运行的SpringBoot应用。结尾的斜杠非常重要。它意味着/api/user这个请求会被转发为http://127.0.0.1:8080/user。如果没有结尾的斜杠,则会转发为http://127.0.0.1:8080/api/user,这通常会导致后端接口404。这是新手最容易踩的坑之一。proxy_set_header: 这几行将客户端的真实IP、协议等信息传递给后端应用,对于日志记录和某些安全策略非常重要。
再次执行sudo nginx -t和sudo systemctl reload nginx使配置生效。现在,前端页面中对/api/xxx的请求就会被Nginx正确转发到后端服务了。
4.2 将SpringBoot应用配置为系统服务
用java -jar &运行应用,一旦终端关闭或服务器重启,应用就停止了。我们需要将其注册为系统服务,实现守护进程、开机自启和集中日志管理。
这里我们使用systemd,它是现代Linux发行版的标准服务管理工具。
创建服务单元文件在
/etc/systemd/system/目录下创建一个以.service结尾的文件,例如myapp-backend.service。sudo vim /etc/systemd/system/myapp-backend.service编写服务配置将以下内容写入文件,请根据你的实际路径修改
ExecStart、WorkingDirectory等参数。[Unit] Description=My SpringBoot Backend Application After=network.target syslog.target [Service] Type=simple User=appuser # 建议创建一个非root用户来运行服务,这里假设是appuser Group=appuser WorkingDirectory=/home/myapp/backend ExecStart=/usr/bin/java -Xms256m -Xmx512m -jar myapp-0.0.1-SNAPSHOT.jar # 或者指定配置文件:-jar myapp.jar --spring.config.location=/home/myapp/backend/application-prod.yml ExecStop=/bin/kill -15 $MAINPID Restart=on-failure RestartSec=10 StandardOutput=journal StandardError=journal [Install] WantedBy=multi-user.target配置详解:
User/Group: 使用非root用户运行服务是重要的安全实践。你需要提前创建这个用户:sudo useradd -r -s /bin/false appuser,并确保该用户对Jar包和日志目录有读写权限。WorkingDirectory: 服务的工作目录,应用生成的日志文件等会在这里。ExecStart: 启动命令。-Xms和-Xmx是JVM堆内存参数,根据你的应用实际情况调整。Restart: 配置为失败时自动重启,提高服务的健壮性。
设置权限并启动服务
# 重新加载systemd配置 sudo systemctl daemon-reload # 启动服务 sudo systemctl start myapp-backend # 设置开机自启 sudo systemctl enable myapp-backend # 查看服务状态 sudo systemctl status myapp-backend如果状态显示为
active (running),恭喜你,后端服务已经成功守护进程化了。查看应用日志服务日志由
systemd的journal管理,可以通过以下命令查看:sudo journalctl -u myapp-backend -f # -f 表示实时跟踪日志你也可以在SpringBoot的
application.properties或application.yml中配置将日志输出到文件,方便管理和切割。
至此,一个基本的Vue+SpringBoot前后端分离项目已经在麒麟系统上部署完成。用户通过80端口访问Nginx,Nginx提供前端页面并代理API请求到后端8080端口的SpringBoot服务,后端服务以系统服务的形式稳定运行。
5. 进阶配置、优化与故障排查
基础部署完成后,为了生产环境的稳定和高可用,我们还需要考虑一些进阶配置和优化点。
5.1 使用域名与HTTPS配置
如果拥有域名,建议配置域名并启用HTTPS,这不仅是安全最佳实践,也对SEO等有好处。
- 域名解析:在域名服务商处将你的域名A记录解析到服务器公网IP。
- 修改Nginx配置:将
server_name改为你的域名。 - 申请SSL证书:可以使用Let‘s Encrypt的免费证书,通过Certbot工具自动化申请和续期。
Certbot会自动完成证书申请、验证和Nginx配置更新。它会将HTTP请求重定向到HTTPS,并配置好证书路径。# 以基于CentOS系统为例,安装Certbot sudo yum install -y certbot python3-certbot-nginx # 运行Certbot,它会自动修改你的Nginx配置 sudo certbot --nginx -d your_domain.com
5.2 前端路由与后端跨域问题
在前后端分离架构中,有两个经典问题:
1. 前端路由刷新404这个问题在Vue Router的history模式下会出现。当用户直接访问一个前端路由(如/dashboard)或刷新页面时,Nginx会去root目录下找/dashboard这个文件或目录,显然找不到,于是返回404。我们在之前的Nginx配置中已经通过try_files $uri $uri/ /index.html;解决了这个问题。它的作用是:先尝试找匹配的文件或目录,如果都找不到,最后返回/index.html,由Vue应用内部的路由系统来处理。
2. 跨域问题(CORS)在开发阶段,我们经常通过Vue CLI的代理或配置后端允许跨域来解决。在生产环境,由于我们使用了Nginx反向代理,前端(浏览器)访问的是同一个域名和端口(Nginx的80/443),API请求被Nginx转发,实际上不存在跨域问题。因此,只要Nginx代理配置正确,生产环境通常无需额外处理CORS。
但是,如果你的后端服务还需要被其他非同一域名下的前端直接调用,则需要在SpringBoot后端配置CORS。例如,在Spring Boot的配置类中添加:
@Configuration public class WebConfig implements WebMvcConfigurer { @Override public void addCorsMappings(CorsRegistry registry) { registry.addMapping("/api/**") // 允许跨域的路径 .allowedOrigins("https://your-frontend-domain.com") // 允许的源 .allowedMethods("GET", "POST", "PUT", "DELETE", "OPTIONS") // 允许的方法 .allowCredentials(true); // 是否允许发送Cookie } }5.3 性能优化与监控
1. Nginx优化
- 连接数与缓冲区:根据服务器性能和预期并发,调整
worker_connections,keepalive_timeout,client_max_body_size(文件上传大小限制)等参数,在主配置文件/etc/nginx/nginx.conf中修改。 - 启用Gzip压缩:压缩文本资源,显著减少传输体积。在Nginx配置中添加或启用:
gzip on; gzip_vary on; gzip_min_length 1024; gzip_types text/plain text/css text/xml text/javascript application/javascript application/xml+rss application/json;
2. SpringBoot JVM优化
- 在
systemd服务文件的ExecStart中调整JVM参数是关键。除了堆内存(-Xms,-Xmx),还可以考虑:-XX:+UseG1GC:使用G1垃圾收集器,通常能提供更好的延迟和吞吐量平衡。-XX:MaxGCPauseMillis=200:设置期望的最大GC停顿时间目标。-Xlog:gc*:file=/home/myapp/backend/gc.log:time:输出GC日志以便分析。 示例:ExecStart=/usr/bin/java -Xms512m -Xmx1024m -XX:+UseG1GC -XX:MaxGCPauseMillis=200 -jar myapp.jar
3. 日志管理
- Nginx日志:访问日志和错误日志默认在
/var/log/nginx/。可以使用logrotate工具进行日志切割和归档,防止日志文件过大。 - 应用日志:建议在SpringBoot的
application-prod.yml中配置日志输出到文件,并按日期或大小滚动。例如使用Logback配置。
5.4 常见问题与排查技巧实录
部署过程中难免会遇到问题,这里记录几个我踩过的坑和排查思路。
问题1:Nginx启动失败或配置重载失败
- 现象:执行
sudo systemctl start nginx或sudo nginx -s reload失败。 - 排查:
- 首先运行
sudo nginx -t检查配置文件语法。它会精确指出哪一行有错误。 - 检查端口占用:
sudo lsof -i:80或sudo netstat -tlnp | grep :80,看80端口是否被其他程序(如Apache、另一个Nginx实例)占用。 - 检查SELinux:如果语法和端口都没问题,可能是SELinux阻止了Nginx访问前端目录。可以暂时禁用SELinux测试,或使用
chcon命令修改目录安全上下文。
- 首先运行
问题2:前端页面能打开,但所有API请求都报404或502错误
- 现象:浏览器开发者工具中,网络请求显示404或502。
- 排查:
- 404:首先检查Nginx代理配置的
proxy_pass地址和路径是否正确。重点检查结尾的斜杠。同时,确认后端SpringBoot应用是否真的在运行并监听对应端口:sudo systemctl status myapp-backend和sudo lsof -i:8080。 - 502 Bad Gateway:这通常意味着Nginx无法连接到后端服务。确认后端服务已启动且监听端口正确。检查防火墙是否开放了8080端口(如果是本机转发,通常不需要,但安全策略严格的服务器可能需要)。查看Nginx错误日志:
sudo tail -f /var/log/nginx/error.log,里面通常会有更具体的连接失败原因。
- 404:首先检查Nginx代理配置的
问题3:后端服务启动失败
- 现象:
sudo systemctl status myapp-backend显示failed或inactive。 - 排查:
- 查看详细日志:
sudo journalctl -u myapp-backend -n 50 --no-pager查看最近50行日志。错误信息通常会直接显示,例如:Jar包找不到、端口被占用、数据库连接失败、配置文件错误等。 - 检查文件权限:确保运行服务的用户(如
appuser)对Jar包、工作目录以及可能用到的外部配置文件、日志目录有读写和执行权限。 - 检查端口占用:
sudo lsof -i:8080,看8080端口是否已被其他进程占用。 - 内存不足:如果JVM申请的内存超过系统可用内存,会导致启动失败。检查
-Xmx参数设置是否合理,以及服务器剩余内存free -h。
- 查看详细日志:
问题4:静态资源(JS/CSS/图片)加载失败或未更新
- 现象:页面样式错乱,或修改了前端代码重新构建上传后,浏览器看到的还是旧版本。
- 排查:
- 浏览器缓存:这是最常见的原因。在Nginx配置中,我们已经为静态资源设置了长期缓存(
expires 1y)。这意味着浏览器在一年内都不会再向服务器请求这个文件。解决方案:在构建前端时,使用Webpack等工具的哈希功能,让文件名随内容变化(如app.abc123.js)。这样,文件内容一变,URL就变了,浏览器自然会请求新文件。Vue CLI默认就启用了这个功能。 - Nginx缓存:如果配置了Nginx代理缓存,可能需要清理。检查Nginx配置。
- 文件路径错误:检查Nginx配置中的
root指令路径是否正确,以及上传的dist文件是否完整覆盖了旧文件。
- 浏览器缓存:这是最常见的原因。在Nginx配置中,我们已经为静态资源设置了长期缓存(
部署是一个系统工程,从环境准备到服务上线,每一步都需要仔细核对。尤其是在国产化操作系统上,可能会遇到一些依赖库版本、路径差异等特定问题,保持耐心,善用搜索引擎和日志排查工具,大部分问题都能找到解决方案。将上述步骤脚本化、文档化,是提升后续部署效率和团队协作能力的好习惯。