项目上线

title:
date:
updated:
tags:
categories:
keywords:
description:
top_img:
comments:
cover:
toc:
toc_number:
toc_style_simple:
copyright:
copyright_author:
copyright_author_href:
copyright_url:
copyright_info:
mathjax:
katex:
aplayer:
highlight_shrink:
aside:
swiper_index: 1
top_group_index: 1
background: “#fff”

img

img

服务器准备

服务器购买与初始化

  1. 购买链接:https://cloud.tencent.com/act/pro/Featured?from=22872

其他平台也可以,总之就是购买轻量级服务器!

  1. 重置密码:

点击右上角重置密码,设置服务器“操作”密码

宝塔面板配置和使用

就是对服务器图形化界面,类似我们平时看到的电脑桌面。在面板上,我们可以更易安装,管理和使用一些环境(mysql,redis)。

  1. 服务器开放防火墙的宝塔端口8888

我们之后再服务器上安装的任何环境都需要将其的端口的防火墙打开

  1. 拿到宝塔面盘登录初值账号密码

在这里我们可以看到宝塔面板的界面浏览器地址,在浏览器上输入地址就可以访问<font style="color:rgba(0, 0, 0, 0.9);">http://106.54.227.250:8888/tencentcloud</font>

点击登录链接,即可跳转到命令行界面,输入sudo /etc/init.d/bt default,即可获得面板的初始账号和密码

  1. 访问地址,使用获取到的账号密码登录即可

  1. 进入后改一下账号和密码(用自己熟悉的,之后用的时候就方便了)

在服务器上安装我们需要的环境

node

  1. 点击安装,直接安装node

  1. 点即Node版本管理器,选择一个LTS(稳定版)安装即可

mysql

同理,点击弹出来的安装即可()

redis

第三方连接

用户名默认为:default

Java

maven

服务部署梳理

前端:http://ip

后端:http://ip/api,实际运行在8120端口

nginx:80端口(识别到api,然后转发到8120端口)

数据库:3306

redis:6379

java

maven

对象存储:第三方

前端部署

1
2
3
location / {
try_files $uri $uri/index.html /index.html;
}

后端部署

后端部署上线真的是难啊,真的不简单

  1. 配置线上环境 **application-prod.yml**
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
# 线上配置文件
server:
port: 8101
spring:
# 数据库配置
datasource:
driver-class-name: com.mysql.cj.jdbc.Driver
url: jdbc:mysql://106.54.227.250:3306/xingdada
username: xingdada
password: 123456
# Redis 配置
redis:
database: 1
host: 106.54.227.250
port: 6379
password: redis
# 分库分表配置(开源代码部署可忽略)
shardingsphere:
#数据源配置
datasource:
# 多数据源以逗号隔开即可
names: xingdada
xingdada:
type: com.zaxxer.hikari.HikariDataSource
driver-class-name: com.mysql.cj.jdbc.Driver
jdbc-url: jdbc:mysql://106.54.227.250:3306/xingdada
username: xingdada
password: 123456
# 规则配置
rules:
sharding:
# 分片算法配置
sharding-algorithms:
# 自定义分片规则名
answer-table-inline:
## inline 类型是简单的配置文件里面就能写的类型,其他还有自定义类等等
type: INLINE
props:
algorithm-expression: user_answer_$->{appId % 2}
tables:
user_answer:
actual-data-nodes: xingdada.user_answer_$->{0..1}
# 分表策略
table-strategy:
standard:
sharding-column: appId
sharding-algorithm-name: answer-table-inline
mybatis-plus:
configuration:
# 生产环境关闭日志
log-impl: ''
# 接口文档配置
knife4j:
basic:
enable: true
username: root
password: 123456
# AI配置
ai:
apiKey: 318a5c7d0deb4350aa49b8acf98e7ae0.1Q2SDxDhWVS8vl07
  1. 打包

1)点击idea右侧边栏Maven,点击1按钮禁用测试(打包他会先将你的测试给运行),然后点击package打包即可

注:如果其中出现报错,不要着急,按照他的步骤一步一步改就行,大部分都是简单的文件/依赖多余的问题)

2)查看包位置

  1. 上传文件

将jar包拖入,然后点击上传按钮即可上传!

  1. 部署

1)点击左边栏网站按钮,然后点击左侧Java项目,接着点击添加Java项目

1
2
/www/server/java/jdk1.8.0_371/bin/java -jar -Xmx512M -Xms256M /www/wwwroot/xingdada-backend-0.0.1-SNAPSHOT.jar
--server.port=8101 --spring.profiles.active=prod

2)– 成功就不看这一步 –

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
mysql -u root -p

DROP USER 'xingdada'@'localhost';
DROP USER 'xingdada'@'%';

CREATE USER 'xingdada'@'localhost' IDENTIFIED BY 'YourStrongPassword';
CREATE USER 'xingdada'@'%' IDENTIFIED BY 'YourStrongPassword';

GRANT ALL PRIVILEGES ON *.* TO 'xingdada'@'localhost' WITH GRANT OPTION;
GRANT ALL PRIVILEGES ON *.* TO 'xingdada'@'%' WITH GRANT OPTION;

FLUSH PRIVILEGES;

SELECT Host, User, Grant_priv FROM mysql.user WHERE User = 'xingdada';
# 权限检验:如果出现 Y ,即成功了
SHOW GRANTS FOR 'xingdada'@'localhost';

SELECT User, Host FROM mysql.user;
mysql> SELECT User, Host FROM mysql.user WHERE User = 'xingdada';
+----------+-----------+
| User | Host |
+----------+-----------+
| xingdada | % |
| xingdada | localhost |
+----------+-----------+
  1. 成功!

nginx

1
2
3
4
5
6
7
8
location /api {
proxy_pass http://127.0.0.1:8101;
proxy_set_header Host $proxy_host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_buffering off;
proxy_set_header Connection "";
}

绑定域名

前端项目访问:

用户输入网址 => 域名解析服务器(把网址解析为ip地址/交给其他的域名解析服务) => 服务器 => nginx接受请求,找到对应的文件,返回文件给前端 => 前端加载文件 => 前端加载到浏览器 => 渲染页面

后端项目访问:

用户输入网址 => 防火墙 => 域名解析服务器 => 服务器 => 后端项目(8080端口)

前端绑定

后端绑定

nginx反向代理:替服务器接受请求,转发请求

跨域

浏览器为了用户的安全,仅允许同域名、同端口的服务器发送请求

解决方法:

  1. 把域名改成相同的
  2. 网关支持Nginx

让服务器告诉浏览器,允许跨域(返回cross-origin-allow响应头)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
location ^~ /api/ {
proxy_pass http://127.0.0.1:8101/api/;
add_header 'Access-Control-Allow-Origin' $http_origin;
add_header 'Access-Control-Allow-Credentials' 'true';
add_header Access-Control-Allow-Methods 'GET, POST, OPTIONS';
add_header Access-Control-Allow-Headers '*';
if ($request_method = 'OPTIONS') {
add_header 'Access-Control-Allow-Credentials' 'true';
add_header 'Access-Control-Allow-Origin' $http_origin;
add_header 'Access-Control-Allow-Methods' 'GET, POST, OPTIONS';
add_header 'Access-Control-Allow-Headers' 'DNT,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Range';
add_header 'Access-Control-Max-Age' 1728000;
add_header 'Content-Type' 'text/plain; charset=utf-8';
add_header 'Content-Length' 0;
return 204;
}
}
  1. 修改后端服务
    • 配置@CrossOrigin注解
    • 添加web全局请求拦截器
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
package com.xingheng.xingdada.config;

import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.CorsRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;

/**
* 全局跨域配置
*
*/
@Configuration
public class CorsConfig implements WebMvcConfigurer {

@Override
public void addCorsMappings(CorsRegistry registry) {
// 覆盖所有请求
registry.addMapping("/**")
// 允许发送 Cookie
.allowCredentials(true)
// 放行哪些域名(必须用 patterns,否则 * 会和 allowCredentials 冲突)
.allowedOriginPatterns("*")
.allowedMethods("GET", "POST", "PUT", "DELETE", "OPTIONS")
.allowedHeaders("*")
.exposedHeaders("*");
}
}
- 定义新的corsFilter Bean

数据库总是自动停止解决

1
2
3
4
5
pgrep -x mysqld &> /dev/null
if [ $? -ne 0 ];then
bash /www/server/panel/script/rememory.sh
/etc/init.d/mysqld start
fi

106.54.227.250

不要的代码

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
package com.xingheng.xingdada;

import cn.hutool.json.JSONUtil;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.xingheng.xingdada.model.entity.UserAnswer;
import com.xingheng.xingdada.service.UserAnswerService;
import org.junit.jupiter.api.Test;
import org.springframework.boot.test.context.SpringBootTest;

import javax.annotation.Resource;

@SpringBootTest
public class UserAnswerShardingTest {

@Resource
private UserAnswerService userAnswerService;

@Test
void test() {

UserAnswer userAnswer1 = new UserAnswer();

userAnswer1.setAppId(1L);
userAnswer1.setUserId(1L);
userAnswer1.setChoices("1");
userAnswerService.save(userAnswer1);

UserAnswer userAnswer2 = new UserAnswer();
userAnswer2.setAppId(2L);
userAnswer2.setUserId(1L);
userAnswer2.setChoices("2");
userAnswerService.save(userAnswer2);

UserAnswer userAnswerOne = userAnswerService.getOne(Wrappers.lambdaQuery(UserAnswer.class).eq(UserAnswer::getAppId, 1L));
System.out.println(JSONUtil.toJsonStr(userAnswerOne));

UserAnswer userAnswerTwo = userAnswerService.getOne(Wrappers.lambdaQuery(UserAnswer.class).eq(UserAnswer::getAppId, 2L));
System.out.println(JSONUtil.toJsonStr(userAnswerTwo));
}
}

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
package com.xingheng.xingdada;

import com.xingheng.xingdada.controller.QuestionController;
import com.xingheng.xingdada.model.dto.question.AiGenerateQuestionRequest;
import org.junit.jupiter.api.Test;
import org.springframework.boot.test.context.SpringBootTest;

import javax.annotation.Resource;

@SpringBootTest
public class QuestionControllerTest {
@Resource
private QuestionController questionController;

@Test
void aiGenerateQuestionSSETest() throws InterruptedException {
// 模拟调用
AiGenerateQuestionRequest aiGenerateQuestionRequest = new AiGenerateQuestionRequest();
aiGenerateQuestionRequest.setAppId(3L);
aiGenerateQuestionRequest.setQuestionNumber(10);
aiGenerateQuestionRequest.setOptionNumber(2);

// 模拟普通用户
questionController.aiGenerateQuestionSSETest(aiGenerateQuestionRequest, false);
questionController.aiGenerateQuestionSSETest(aiGenerateQuestionRequest, false);
// 模拟普通用户
questionController.aiGenerateQuestionSSETest(aiGenerateQuestionRequest, true);

Thread.sleep(1000000L);
}
}

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
package com.xingheng.xingdada;

import io.reactivex.Flowable;
import io.reactivex.schedulers.Schedulers;
import org.junit.jupiter.api.Test;
import org.springframework.boot.test.context.SpringBootTest;

import java.util.concurrent.TimeUnit;

@SpringBootTest
public class RxjavaTest {
@Test
public void test() throws InterruptedException {
// 创建数据流(每隔一段时间产生一段流)
Flowable<Long> flowable = Flowable.interval(1, TimeUnit.SECONDS)
.map(i -> +i)
.subscribeOn(Schedulers.io());// 指定执行操作的线程池

// 订阅 Flowable 流,并且打印出每个接受到的数字
flowable
.observeOn(Schedulers.io())
.doOnNext(item -> System.out.println(item.toString()))
.subscribe();

// 主线程睡眠,以便观察到结果
Thread.sleep(10000L);
}

}

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
package com.xingheng.xingdada;

import com.fasterxml.jackson.core.JsonProcessingException;
import com.zhipu.oapi.ClientV4;
import com.zhipu.oapi.Constants;
import com.zhipu.oapi.service.v4.model.ChatCompletionRequest;
import com.zhipu.oapi.service.v4.model.ChatMessage;
import com.zhipu.oapi.service.v4.model.ChatMessageRole;
import com.zhipu.oapi.service.v4.model.ModelApiResponse;
import org.junit.jupiter.api.Test;
import org.springframework.boot.test.context.SpringBootTest;

import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.List;

@SpringBootTest
public class ZhiPuAiTest {
@Resource
private ClientV4 clientV4;
@Test
public void test() {
// 初始化客户端
// ClientV4 client = new ClientV4.Builder("318a5c7d0deb4350aa49b8acf98e7ae0.1Q2SDxDhWVS8vl07").build();
//
List<ChatMessage> messages = new ArrayList<>();
ChatMessage chatMessage = new ChatMessage(ChatMessageRole.USER.value(), "作为一名营销专家,请为智谱开放平台创作一个吸引人的slogan");
messages.add(chatMessage);
// String requestId = String.format(requestIdTemplate, System.currentTimeMillis());

ChatCompletionRequest chatCompletionRequest = ChatCompletionRequest.builder()
.model(Constants.ModelChatGLM4)
.stream(Boolean.FALSE)
.invokeMethod(Constants.invokeMethod)
.messages(messages)
.maxTokens(100)
.build();

ModelApiResponse invokeModelApiResp = clientV4.invokeModelApi(chatCompletionRequest);
System.out.println("model output:" + invokeModelApiResp.getData().getChoices().get(0));
}
}