Java牛客项目课_仿牛客网讨论区_第八章
2021/5/21 14:25:37
本文主要是介绍Java牛客项目课_仿牛客网讨论区_第八章,对大家解决编程问题具有一定的参考价值,需要的程序猿们随着小编来一起学习吧!
文章目录
- 第八章、项目发布与总结
- 8.1、 单元测试
- 8.2、项目监控
- 8.3、项目部署
- 宝塔面板、yum、rpm、压缩包 安装 unzip、Java1.8、Maven、MySQL、Redis、Kafka、ElasticSearch和ik分词器、wkhtmltopdf、xvfb、Tomcat、Nginx。
- 如何访问到我们的项目:浏览器->Nginx->Tomcat。如何一个Tomcat部署多个项目。
- 把能在Windows上运行的项目改为能在Linux服务器上运行。然后把项目丢到服务器上,用服务器上的Maven编译打包,再把ROOT.war丢到Tomcat的wabapp目录下,启动Tomcat。
- 为了部署到服务器,我在视频课项目外额外加的代码。
- 遇到的错误和解决:
- 1、Maven编译打包项目报错:Failed to execute goal org.apache.maven.plugins:maven-resources-plugin:3.2.0:resources
- 2、Tomcat启动时的启动日志中的报错:Caused by: java.net.BindException: Address already in use
- 3、`/tmp/community/log_error.log`日志中关于Kafka的报错:Exception thrown when sending a message with key='null'
- 4、服务器上的MySQL启动失败:Starting MySQL...The server quit without updating PID file
- 5、重启Linux服务器上的elasticsearch时,需要做的步骤
- 8.4、项目总结
- 8.5、常见面试题
第八章、项目发布与总结
8.1、 单元测试
Spring Boot Testing
- 依赖:spring-boot-starter-test
- 包括:Junit、Spring Test、AssertJ、…
Test Case - 要求:保证测试方法的独立性。
-
步骤:初始化数据、执行测试代码、验证测试结果、清理测试数据。
-
常用注解:@BeforeClass、@AfterClass、@Before、@After。
@BeforeClass:注解的方法在该类加载前运行
@AfterClass:注解的方法在该类销毁后运行
@Before:注解的方法在该类中的任何测试方法执行前运行
@After:注解的方法在该类中的任何测试方法执行后运行
后两个注解,方便我们在没有条件时,创造条件来进行测试。比如测试数据库的增删改查,那么每个方法测试前,先在用@Before注解的方法里新建一条数据库中的数据,运行完测试方法后,再在用@After注解的方法里销毁测试的数据。
执行测试类时,会依次执行测试类的所有测试方法。
于是,在一个测试类中写好测试数据库中某张表的增删改查的方法
后,可以直接执行这个测试类,用断言Assert比较测试结果和预期结果是否一致,一致就程序执行成功,不一致就会抛出异常。于是,只要执行这个测试类,就可以把数据库这张表的所有业务service方法测试完成,如果没有报错,就说明数据库这张表的所有业务service方法都正确,如果有某个测试方法抛异常,就说明该测试方法测试的方法有错误。
package com.nowcoder.community; import com.nowcoder.community.entity.DiscussPost; import com.nowcoder.community.service.DiscussPostService; import org.junit.*; import org.junit.runner.RunWith; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.context.SpringBootTest; import org.springframework.test.context.ContextConfiguration; import org.springframework.test.context.junit4.SpringRunner; import java.util.Date; @RunWith(SpringRunner.class) @SpringBootTest @ContextConfiguration(classes = CommunityApplication.class) public class SpringBootTests { @Autowired private DiscussPostService discussPostService; private DiscussPost data; //@BeforeClass和@AfterClass修饰的方法都必须用static修饰 @BeforeClass public static void beforeClass() { System.out.println("beforeClass"); } @AfterClass public static void afterClass() { System.out.println("afterClass"); } @Before public void before() { System.out.println("before"); // 初始化测试数据 data = new DiscussPost(); data.setUserId(111); data.setTitle("Test Title"); data.setContent("Test Content"); data.setCreateTime(new Date()); discussPostService.addDiscussPost(data); } @After public void after() { System.out.println("after"); // 删除测试数据 discussPostService.updateStatus(data.getId(), 2); } @Test public void test1() { System.out.println("test1"); } @Test public void test2() { System.out.println("test2"); } @Test public void testFindById() { DiscussPost post = discussPostService.findDiscussPostById(data.getId()); Assert.assertNotNull(post); Assert.assertEquals(data.getTitle(), post.getTitle()); Assert.assertEquals(data.getContent(), post.getContent()); } @Test public void testUpdateScore() { int rows = discussPostService.updateScore(data.getId(), 2000.00); Assert.assertEquals(1, rows); DiscussPost post = discussPostService.findDiscussPostById(data.getId()); Assert.assertEquals(2000.00, post.getScore(), 2); } }
8.2、项目监控
Spring Boot Actuator
- Endpoints:监控应用的入口,Spring Boot内置了很多端点,也支持自定义端点。
- 监控方式:HTTP 或 JMX。
- 访问路径:例如“/actuator/health”。
- 注意事项:按需配置暴露的端点,并对所有端点进行权限控制。
访问:http://localhost:8080/community/actuator/端点名字(如health、info、loggers,也可以是自定义端点的名字,如database)
返回:JSON字符串。
例子:
访问路径 | 用处 |
---|---|
http://localhost:8080/community/actuator/health | 当前服务的健康状况。返回:{“status”:“DOWN”} |
http://localhost:8080/community/actuator/info | 返回服务端的一些相关信息。如果没有,返回:{} |
http://localhost:8080/community/actuator/beans | 返回应用中所有的bean。返回的内容太多,建议写个程序来分析,或者安装和actuator有关的工具来分析。 |
http://localhost:8080/community/actuator/loggers | 所有日志 |
pom.xml
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-actuator</artifactId> </dependency>
application.propertise
# actuator management.endpoints.web.exposure.include=* # 暴露哪些端点,'*'代表全部。 management.endpoints.web.exposure.exclude=info,caches # 排除哪些端点,就是哪些端点不暴露。
DatabaseEndpoint.java
package com.nowcoder.community.actuator; import com.nowcoder.community.util.CommunityUtil; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.actuate.endpoint.annotation.Endpoint; import org.springframework.boot.actuate.endpoint.annotation.ReadOperation; import org.springframework.stereotype.Component; import javax.sql.DataSource; import java.sql.Connection; import java.sql.SQLException; //这个自定义端点用来监控数据库的连接是否正常 @Component @Endpoint(id = "database")//自定义端点的id为database,好通过id访问它。即访问路径:http://localhost:8080/community/actuator/database。 public class DatabaseEndpoint { private static final Logger logger = LoggerFactory.getLogger(DatabaseEndpoint.class); @Autowired private DataSource dataSource; @ReadOperation //@ReadOperation表明这个方法只能通过get请求来访问。@WriteOperation注释的方法只能通过post/put请求来访问 public String checkConnection() { try ( Connection conn = dataSource.getConnection(); ) { return CommunityUtil.getJSONString(0, "获取连接成功!"); // 返回:{"msg":"获取连接成功!","code":0} } catch (SQLException e) { logger.error("获取连接失败:" + e.getMessage()); return CommunityUtil.getJSONString(1, "获取连接失败!"); } } }
8.3、项目部署
正向代理即是客户端代理, 代理客户端, 服务端不知道实际发起请求的客户端。
反向代理即是服务端代理, 代理服务端, 客户端不知道实际提供服务的服务端。
一句话总结:正向代理隐藏真实客户端,反向代理隐藏真实服务端。
老师想的压缩包安装部分。
宝塔面板、yum、rpm、压缩包 安装 unzip、Java1.8、Maven、MySQL、Redis、Kafka、ElasticSearch和ik分词器、wkhtmltopdf、xvfb、Tomcat、Nginx。
yum安装unzip
# 安装unzip,用于解压zip包 [root@wu1 /]# yum list unzip* # yum list xx*,该命令在根目录"/"下才有效果 [root@wu1 /]# yum install -y unzip.x86_64
rpm安装Java1.8(狂神说)
视频课:【狂神说Java】Linux最通俗易懂的教程阿里云真实环境学习_哔哩哔哩 (゜-゜)つロ 干杯~-bilibili
视频课中的环境变量有错,按下面这个环境变量。
[root@wu1 apache-maven-3.8.1]# vim /etc/profile # 环境变量,在最后追加 JAVA_HOME=/usr/java/jdk1.8.0_281-amd64 CLASSPATH=%JAVA_HOME%/lib:%JAVA_HOME%/jre/lib PATH=$PATH:$JAVA_HOME/bin:$JAVA_HOME/jre/bin export PATH CLASSPATH JAVA_HOME [root@wu1 apache-maven-3.8.1]# source /etc/profile # 让配置文件/etc/profile生效 [root@wu1 /]# java -version # 狂神说的Java java version "1.8.0_281" Java(TM) SE Runtime Environment (build 1.8.0_281-b09) Java HotSpot(TM) 64-Bit Server VM (build 25.281-b09, mixed mode)
yum安装Java环境(牛客项目课)
# 安装Java环境。这个安装完,Java在云服务器上就装了两个,一个是狂神说的,一个是牛客网项目课的,就下面这个。 [root@wu1 /]# yum list java* [root@wu1 /]# yum install -y java-latest-openjdk.x86_64 # 此时,我用命令`java -version`还是显示"1.8.0_281",我也只需要一个Java环境,就把牛客项目课的openJDK删掉了。就是云服务器上只有狂神说的1.8的Java环境。 [root@wu1 community]# rpm -qa|grep java # 查询服务器中是否有openJDK java-latest-openjdk-16.0.0.0.36-1.rolling.el7.x86_64 python-javapackages-3.4.1-11.el7.noarch javapackages-tools-3.4.1-11.el7.noarch tzdata-java-2021a-1.el7.noarch java-latest-openjdk-headless-16.0.0.0.36-1.rolling.el7.x86_64 [root@wu1 community]# rpm -ev java-latest-openjdk-16.0.0.0.36-1.rolling.el7.x86_64 # 删除openJDK Preparing packages... java-latest-openjdk-1:16.0.0.0.36-1.rolling.el7.x86_64 [root@wu1 community]# rpm -ev java-latest-openjdk-headless-16.0.0.0.36-1.rolling.el7.x86_64 Preparing packages... java-latest-openjdk-headless-1:16.0.0.0.36-1.rolling.el7.x86_64
压缩包安装Maven
# 安装Maven [root@wu1 ~]# ll total 9356 -rw-r--r-- 1 root root 9536838 Apr 28 16:57 apache-maven-3.8.1-bin.tar.gz -rw-r--r-- 1 root root 92 Apr 11 20:48 dump.rdb -rw-r--r-- 1 root root 12 Apr 16 17:19 hi.html -rw-r--r-- 1 root root 25386 Jan 9 12:00 install.sh -rw-r--r-- 1 root root 2740 Aug 23 2020 update.sh [root@wu1 ~]# tar -zxvf apache-maven-3.8.1-bin.tar.gz -C /opt [root@wu1 ~]# cd /opt [root@wu1 opt]# cd apache-maven-3.8.1/ [root@wu1 apache-maven-3.8.1]# pwd /opt/apache-maven-3.8.1 [root@wu1 apache-maven-3.8.1]# vim /etc/profile # 在最后追加一行 export PATH=$PATH:/opt/apache-maven-3.8.1/bin [root@wu1 apache-maven-3.8.1]# source /etc/profile # 让配置文件/etc/profile生效 [root@wu1 apache-maven-3.8.1]# echo $PATH # 打印出环境变量看一下 /usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/usr/java/jdk1.8.0_281-amd64/bin:/usr/java/jdk1.8.0_281-amd64/jre/bin:/usr/java/jdk1.8.0_281-amd64/bin:/usr/java/jdk1.8.0_281-amd64/jre/bin:/root/bin:/usr/java/jdk1.8.0_281-amd64/bin:/usr/java/jdk1.8.0_281-amd64/jre/bin:/opt/apache-maven-3.8.1:/usr/java/jdk1.8.0_281-amd64/bin:/usr/java/jdk1.8.0_281-amd64/jre/bin:/opt/apache-maven-3.8.1/bin [root@wu1 apache-maven-3.8.1]# mvn -version # 安装好maven了 Apache Maven 3.8.1 (05c21c65bdfed0f71a2f2ada8b84da59348c4c5d) Maven home: /opt/apache-maven-3.8.1 Java version: 1.8.0_281, vendor: Oracle Corporation, runtime: /usr/java/jdk1.8.0_281-amd64/jre Default locale: en_US, platform encoding: UTF-8 OS name: "linux", version: "3.10.0-1062.18.1.el7.x86_64", arch: "amd64", family: "unix" # 配置Maven [root@wu1 conf]# vim /opt/apache-maven-3.8.1/conf/settings.xml # 下方复制到两个mirrors里 <mirror> <id>alimaven</id> <name>aliyun maven</name> <url>http://maven.aliyun.com/nexus/content/groups/public/</url> <mirrorOf>central</mirrorOf> </mirror>
宝塔面板安装MySQL
MySQL :: Download MySQL Yum Repository
宝塔linux面板命令大全 - 宝塔面板
# 安装mysql [root@wu1 ~]# yum install -y mysql80-community-release-el8-1.noarch.rpm [root@wu1 ~]# cd / [root@wu1 /]# yum list mysql* [root@wu1 /]# yum install -y mysql-community-server.x86_64 或者 宝塔面板一键安装。我用的宝塔面板安装的mysql8 [root@wu1 /]# systemctl start mysqld [root@wu1 /]# systemctl status mysqld [root@wu1 ~]# cd /www/server/panel && python tools.py root a1b2c3 # 强制修改MySQL管理(root)密码,如要改成a1b2c3 [root@wu1 panel]# mysql -u root -p Enter password: Welcome to the MySQL monitor. Commands end with ; or \g. Your MySQL connection id is 8 Server version: 8.0.23 Source distribution 。。。 mysql> create database community; mysql> use community mysql> source /root/init_sql/init_schema.sql mysql> source /root/init_sql/init_data.sql mysql> source /root/init_sql/tables_mysql_innodb.sql mysql> show tables; mysql> select id,username,header_url from user; mysql> update user set header_url ='http://images.nowcoder.com/head/666t.png' where header_url like '%localhost%'; mysql> exit Bye
yum安装Redis
# 安装redis。安装完这个redis,我电脑上总共安装了两个redis,一个是狂神说的redis,一个是按以下方法安装的redis。可以启动这个关闭那个,两个Redis里的数据是不一样的。 [root@wu1 panel]# cd / [root@wu1 /]# yum list redis* Loaded plugins: fastestmirror Loading mirror speeds from cached hostfile * centos-sclo-rh: mirrors.aliyun.com Available Packages redis.x86_64 3.2.12-2.el7 epel redis-trib.noarch 3.2.12-2.el7 epel [root@wu1 /]# yum install -y redis.x86_64 [root@wu1 bin]# systemctl start redis [root@wu1 bin]# systemctl status redis [root@wu1 bin]# redis-cli 127.0.0.1:6379> exit
压缩包安装Kafka
# 安装Kafka [root@wu1 ~]# tar -zvxf kafka_2.13-2.7.0.tgz -C /opt [root@wu1 ~]# /opt/kafka_2.13-2.7.0/bin/zookeeper-server-start.sh -daemon /opt/kafka_2.13-2.7.0/config/zookeeper.properties # 后台启动zookeeper [root@wu1 ~]# nohup /opt/kafka_2.13-2.7.0/bin/kafka-server-start.sh /opt/kafka_2.13-2.7.0/config/server.properties 1>/dev/null 2>&1 & # 后台启动Kafka [1] 4408 [root@wu1 ~]# /opt/kafka_2.13-2.7.0/bin/kafka-topics.sh --list --bootstrap-server localhost:9092 # 没报错就说明启动成功
压缩包安装ElasticSearch和ik分词器
# 安装elasticsearch和ik分词器 [root@wu1 ~]# tar -zvxf /root/elasticsearch-7.12.0-linux-x86_64.tar.gz -C /opt [root@wu1 ~]# unzip -d /opt/elasticsearch-7.12.0/plugins/ik /root/elasticsearch-analysis-ik-7.12.0.zip [root@wu1 ~]# vim /opt/elasticsearch-7.12.0/config/elasticsearch.yml # 取消下方内容的注释,修改以下内容 cluster.name: nowcoder path.data: /tmp/elastic/data path.logs: /tmp/elastic/logs [root@wu1 ~]# vim /opt/elasticsearch-7.12.0/config/jvm.options # 取消下方内容的注释,修改以下内容,这两个参数要顶格写。 -Xms256m -Xmx512m [root@wu1 ~]# groupadd nowcoder [root@wu1 ~]# useradd nowcoder1 -p 123456 -g nowcoder [root@wu1 ~]# cd /opt [root@wu1 opt]# chown -R nowcoder1:nowcoder * [root@wu1 opt]# cd /tmp [root@wu1 tmp]# chown -R nowcoder1:nowcoder * [root@wu1 tmp]# su - nowcoder1 [nowcoder1@wu1 ~]$ /opt/elasticsearch-7.12.0/bin/elasticsearch -d # 后台启动es [nowcoder1@wu1 ~]$ su - Password: [root@wu1 ~]# curl -X GET "localhost:9200/_cat/health?v" # 测试es是否成功启动 epoch timestamp cluster status node.total node.data shards pri relo init unassign pending_tasks max_task_wait_time active_shards_percent 1619627359 16:29:19 nowcoder green 1 1 0 0 0 0 0 0 - 100.0%
yum安装wkhtmltopdf
# yum安装wkhtmltopdf [root@wu1 ~]# cd / [root@wu1 /]# yum list wkhtmltopdf* Loaded plugins: fastestmirror Loading mirror speeds from cached hostfile * centos-sclo-rh: mirrors.aliyun.com Available Packages wkhtmltopdf.x86_64 0.12.4-1.el7 wkhtmltopdf-devel.x86_64 0.12.4-1.el7 [root@wu1 /]# yum install -y wkhtmltopdf.x86_64
yum安装xvfb,让Linux可视化。因为wkhtmltopdf会生成图片,图片是可视化的。
# yum安装xvfb,让Linux可视化。因为wkhtmltopdf会生成图片,图片是可视化的。 [root@wu1 /]# yum list *xvfb* Loaded plugins: fastestmirror Loading mirror speeds from cached hostfile * centos-sclo-rh: mirrors.aliyun.com Available Packages python-xvfbwrapper.noarch 0.2.4-2.el7 epel xorg-x11-server-Xvfb.x86_64 1.20.4-15.el7_9 updates [root@wu1 /]# yum install -y xorg-x11-server-Xvfb.x86_64
测试用wkhtmltopdf生成图片
# 测试用wkhtmltopdf生成图片 [root@wu1 /]# cd /root/test [root@wu1 test]# ll total 0 [root@wu1 test]# xvfb-run --server-args="-screen 0, 1024x768x24" wkhtmltoimage https://www.baidu.com 1.png Loading page (1/2) Rendering (2/2) Warning: Received createRequest signal on a disposed ResourceObject's NetworkAccessManager. This might be an indication of an iframe taking too long to load. Done [root@wu1 test]# ll total 2952 -rw-r--r-- 1 root root 3019976 Apr 29 00:37 1.png [root@wu1 test]# cd /opt [root@wu1 opt]# vim wkhtmltoimage.sh # /opt/wkhtmltoimage.sh文件里只有这一句话 xvfb-run --server-args="-screen 0, 1024x768x24" wkhtmltoimage "$@" [root@wu1 opt]# ll total 2412 drwxr-xr-x 6 nowcoder1 nowcoder 4096 Apr 28 17:01 apache-maven-3.8.1 drwx--x--x 4 nowcoder1 nowcoder 4096 Mar 19 11:15 containerd drwxr-xr-x 9 nowcoder1 nowcoder 4096 Mar 18 14:21 elasticsearch-7.12.0 drwxr-xr-x 7 nowcoder1 nowcoder 4096 Apr 28 23:12 kafka_2.13-2.7.0 drwxrwxr-x 7 nowcoder1 nowcoder 4096 Mar 2 14:14 redis-6.2.1 -rw-r--r-- 1 nowcoder1 nowcoder 2438367 Mar 25 10:35 redis-6.2.1.tar.gz drwxr-xr-x 3 nowcoder1 nowcoder 4096 Mar 13 11:11 rh -rw-r--r-- 1 root root 67 Apr 29 00:39 wkhtmltoimage.sh [root@wu1 opt]# chmod +x wkhtmltoimage.sh [root@wu1 opt]# cd /root/test [root@wu1 test]# /opt/wkhtmltoimage.sh https://www.baidu.com 2.png Loading page (1/2) Rendering (2/2) Warning: Received createRequest signal on a disposed ResourceObject's NetworkAccessManager. This might be an indication of an iframe taking too long to load. Done [root@wu1 test]# ll total 5904 -rw-r--r-- 1 root root 3019976 Apr 29 00:37 1.png -rw-r--r-- 1 root root 3019976 Apr 29 00:40 2.png [root@wu1 test]#
宝塔面板安装Tomcat
# 宝塔面板安装tomcat [root@wu1 test]# vim /etc/profile # 最下方写一句这个 export PATH=$PATH:/www/server/tomcat/bin [root@wu1 test]# source /etc/profile [root@wu1 test]# echo $PATH /usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin:/usr/java/jdk1.8.0_281-amd64/bin:/usr/java/jdk1.8.0_281-amd64/jre/bin:/opt/apache-maven-3.8.1/bin:/www/server/tomcat/bin:/usr/java/jdk1.8.0_281-amd64/bin:/usr/java/jdk1.8.0_281-amd64/jre/bin:/opt/apache-maven-3.8.1/bin:/www/server/tomcat/bin:/root/bin:/usr/java/jdk1.8.0_281-amd64/bin:/usr/java/jdk1.8.0_281-amd64/jre/bin:/opt/apache-maven-3.8.1/bin:/www/server/tomcat/bin
压缩包安装Nginx
# 压缩包安装nginx(下方为yum安装nginx失败) [root@wu1 ~]# cd / [root@wu1 /]# yum list nginx* Loaded plugins: fastestmirror Loading mirror speeds from cached hostfile * centos-sclo-rh: mirrors.aliyun.com Available Packages nginx-all-modules.noarch 1:1.16.1-3.el7 epel nginx-filesystem.noarch 1:1.16.1-3.el7 epel nginx-mod-http-image-filter.x86_64 1:1.16.1-3.el7 epel nginx-mod-http-perl.x86_64 1:1.16.1-3.el7 epel nginx-mod-http-xslt-filter.x86_64 1:1.16.1-3.el7 epel nginx-mod-mail.x86_64 1:1.16.1-3.el7 epel nginx-mod-stream.x86_64 1:1.16.1-3.el7 epel [root@wu1 /]# yum install -y nginx.x86_64 。。。 No package nginx.x86_64 available. Error: Nothing to do # 压缩包安装nginx后 [root@wu1 ~]# vim /usr/local/nginx/conf/nginx.conf # http的大括号里,去掉原先的server,加上下面这个 # http是80端口,https是443端口。默认是80端口,于是访问120.77.151.233会变为120.77.151.233:80,然后被服务器中的nginx映射到120.77.151.233:8080。 upstream myserver{ server 127.0.0.1:8080 max_fails=3 fail_timeout=30s; } server{ listen 80; server_name 120.77.151.233; location / { proxy_pass http://myserver; } } [root@wu1 ~]# /usr/local/nginx/sbin/nginx nginx: [emerg] "upstream" directive is not allowed here in /usr/local/nginx/conf/nginx.conf:88 [root@wu1 ~]# vim /usr/local/nginx/conf/nginx.conf [root@wu1 ~]# /usr/local/nginx/sbin/nginx nginx: [emerg] "server" directive is not allowed here in /usr/local/nginx/conf/nginx.conf:93 [root@wu1 ~]# vim /usr/local/nginx/conf/nginx.conf [root@wu1 ~]# /usr/local/nginx/sbin/nginx nginx: [emerg] bind() to 0.0.0.0:80 failed (98: Address already in use) nginx: [emerg] bind() to 0.0.0.0:80 failed (98: Address already in use) nginx: [emerg] bind() to 0.0.0.0:80 failed (98: Address already in use) nginx: [emerg] bind() to 0.0.0.0:80 failed (98: Address already in use) nginx: [emerg] bind() to 0.0.0.0:80 failed (98: Address already in use) nginx: [emerg] still could not bind() [root@wu1 ~]# killall -9 nginx [root@wu1 ~]# /usr/local/nginx/sbin/nginx # 没输出东西,就代表nginx启动成功
如何访问到我们的项目:浏览器->Nginx->Tomcat。如何一个Tomcat部署多个项目。
如果访问1.1.1.1,会访问1.1.1.1:80,然后被服务器中的nginx映射到1.1.1.1:8080,即访问tomcat中的ROOT项目的首页。如果想访问tomcat下的其他项目,需要用1.1.1.1/community这种形式来访问,如果1.1.1.1有域名nowcoder.com,那么需要用nowcoder.com/community来访问我们自己的项目。
补充知识点:一个tomcat部署多个项目
~~
【狂神说Java】JavaWeb入门到实战_哔哩哔哩 (゜-゜)つロ 干杯~-bilibili。这个视频课是关于tomcat的,讲了,直接把软件放在tomcat的webapp目录下,他默认是localhost:8080/
会访问到webapp/ROOT
项目;而localhost:8080/hello
会访问到webapp/hello
项目;而localhost:8080/hello2
会访问到webapp/hello2
项目。
~~
1.1.1.1
默认为1.1.1.1:80
,nginx把其映射到1.1.1.1:8080
,然后我们可以在tomcat的webapp目录下部署两个war包,一个是ROOT,一个是scau-community。然后一启动tomcat,就会把这两个war包打开为两个文件夹,然后,可以用1.1.1.1
访问ROOT,可以用1.1.1.1/scau-community
访问scau-community
~~
1.1.1.1
是假设的IP,改成你的服务器的IP。
通过删掉ROOT,然后把我们自己的项目打包成ROOT.war来解决,到时候访问1.1.1.1,会访问到我们自己的项目。
把能在Windows上运行的项目改为能在Linux服务器上运行。然后把项目丢到服务器上,用服务器上的Maven编译打包,再把ROOT.war丢到Tomcat的wabapp目录下,启动Tomcat。
接下来,1、去掉/community,2、访问"/“时要访问”/index"。
[root@wu1 ~]# shutdown.sh # 关掉tomcat Using CATALINA_BASE: /www/server/tomcat Using CATALINA_HOME: /www/server/tomcat Using CATALINA_TMPDIR: /www/server/tomcat/temp Using JRE_HOME: /usr/java/jdk1.8.0_281-amd64 Using CLASSPATH: /www/server/tomcat/bin/bootstrap.jar:/www/server/tomcat/bin/tomcat-juli.jar # 可以修改/www/server/tomcat/webapps/ROOT文件夹为ROOT_bak文件夹。 # 但建议直接删除原先的webapp目录下的所有文件。
IDEA项目8.3修改
1、去掉/community
# application.properties server.servlet.context-path= # global.js var CONTEXT_PATH = "";
2、访问"/“时要访问”/index"
# HomeController.java加一个方法 @RequestMapping(path = "/", method = RequestMethod.GET) public String root() { return "forward:/index"; }
3、默认会打成jar包,要使得打包时打成war包
# pom.xml增加<packaging>和<finalName>两行 <name>community</name> <description>nowcoder community</description> <packaging>war</packaging> <build> <finalName>ROOT</finalName> <plugins> <plugin> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-maven-plugin</artifactId> </plugin> </plugins> </build>
4、Windows上日志文件的存放地址和Linux服务器上的日志文件存放地址不一样,其他的一些路径也都不一样。又不方便测试时xx路径,上线时改为yy路径。于是SpringBoot允许一个项目有多套配置文件,开发时一套,上线时一套,也可以有其他的。然后通过一个开关,决定用哪套配置文件。
这里搞两套配置文件,开发一套,生产(上线)一套。
application.properties application-develop.properties application-produce.properties logback-spring.xml logback-spring-develop.xml logback-spring-produce.xml
开关为application.properties,修改时只需要spring.profiles.active=produce/develop,即可。
# profile spring.profiles.active=produce # logback logging.config=classpath:logback-spring-${spring.profiles.active}.xml
5、因为tomcat本身就有启动方法,而我们的项目也有启动的方法,于是需要一个两者间的桥梁,就是下面这个。继承一个类,用来实现该类的父接口的configure方法。
加一个类,CommunityServletInitializer.java
package com.nowcoder.community; import org.springframework.boot.builder.SpringApplicationBuilder; import org.springframework.boot.web.servlet.support.SpringBootServletInitializer; public class CommunityServletInitializer extends SpringBootServletInitializer { //tomcat访问该方法作为入口来运行该项目 @Override protected SpringApplicationBuilder configure(SpringApplicationBuilder builder) { return builder.sources(CommunityApplication.class); //这里指出该项目的main方法所在的类 } }
6、application-develop.properties和application-produce.properties相比,后者修改的地方。
# ServerProperties server.servlet.context-path= # ThymeleafProperties spring.thymeleaf.cache=true # DataSourceProperties # 因为访问的是你自己电脑上的mysql->服务器的mysql,可能两个mysql你设置的用户名密码不一致。 spring.datasource.username=root spring.datasource.password=a1b2c3 # community community.path.domain=http://120.77.151.233 community.path.upload=/tmp/uploads # wk wk.image.command=/opt/wkhtmltoimage.sh wk.image.storage=/tmp/wk-images
7、logback-spring-produce.xml相对于logback-spring-develop.xml修改的地方
<contextName>community</contextName> <property name="LOG_PATH" value="/tmp"/> <!--只改了这里"/tmp"--> <property name="APPDIR" value="community"/>
8、删除生成的target文件
删除target文件遇到的问题和解决方法:IDEA 踩坑之:maven 打包提示 [ERROR] The specified user settings file does not exist…_小白一个-CSDN博客
9、把项目丢到服务器上,用服务器上的Maven编译打包,再把ROOT.war丢到Tomcat的wabapp目录下,启动Tomcat。
把项目打包为zip压缩包,然后上传到服务器的root目录下。
[root@wu1 ~]# unzip -d /root community.zip # -d后面跟放到哪个目录下。 [root@wu1 ~]# cd community [root@wu1 community]# mvn clean package -Dmaven.test.skip=true # 用maven把项目编译并且打包,跳过测试,因为我们前面的测试类写的都不标准,最后单独讲的那个测试才是标准的测试。耗时较长。 [root@wu1 community]# cd target # 来到/root/community/target目录 [root@wu1 target]# ll # 看到ROOT.war文件 [root@wu1 target]# mv ROOT.war /www/server/tomcat/webapps/ [root@wu1 target]# startup.sh # 启动tomcat。虽然立刻返回了信息,但实际上过了一会才启动 Using CATALINA_BASE: /www/server/tomcat Using CATALINA_HOME: /www/server/tomcat Using CATALINA_TMPDIR: /www/server/tomcat/temp Using JRE_HOME: /usr/java/jdk1.8.0_281-amd64 Using CLASSPATH: /www/server/tomcat/bin/bootstrap.jar:/www/server/tomcat/bin/tomcat-juli.jar Tomcat started. [root@wu1 target]# vim /www/server/tomcat/logs/catalina.2021-05-16.log # 查看tomcat的日志,是否启动成功。
tomcat启动日志/www/server/tomcat/logs/catalina.2021-05-16.log
启动成功时提示:
。。。 18-May-2021 23:50:42.348 INFO [main] org.apache.catalina.startup.Catalina.load Initialization processed in 575 ms 18-May-2021 23:50:42.382 INFO [main] org.apache.catalina.core.StandardService.startInternal Starting service Catalina 18-May-2021 23:50:42.383 INFO [main] org.apache.catalina.core.StandardEngine.startInternal Starting Servlet Engine: Apache Tomcat/9.0.0.M18 18-May-2021 23:50:42.402 INFO [main] org.apache.catalina.startup.HostConfig.deployWAR Deploying web application archive /www/server/tomcat/webapps/ROOT.war 18-May-2021 23:50:47.297 INFO [main] org.apache.jasper.servlet.TldScanner.scanJars At least one JAR was scanned for TLDs yet contained no TLDs. Enable debug logging for this logger for a complete list of JARs that were scanned but no TLDs were found in them. Skipping unneeded JARs during scanning can improve startup time and JSP compilation time. 18-May-2021 23:50:58.085 INFO [main] org.apache.catalina.startup.HostConfig.deployWAR Deployment of web application archive /www/server/tomcat/webapps/ROOT.war has finished in 15,682 ms 18-May-2021 23:50:58.100 INFO [main] org.apache.coyote.AbstractProtocol.start Starting ProtocolHandler [http-nio-8080] 18-May-2021 23:50:58.138 INFO [main] org.apache.coyote.AbstractProtocol.start Starting ProtocolHandler [ajp-nio-8009] 18-May-2021 23:50:58.154 INFO [main] org.apache.catalina.startup.Catalina.start Server startup in 15806 ms
部署到服务器上以后,我们就没有办法用工具来调试了,一切都要看日志,所以要习惯于看日志。
为了部署到服务器,我在视频课项目外额外加的代码。
1、项目的启动初始化代码,使得服务器上的项目启动时,从数据库取到所有帖子数据,同步到ElasticSearch中。
加这段代码时,遇到的错:
ElasticSearch创建索引报错:ElasticsearchStatusException [type=resource_already_exists_exception, reason=index already exists]_夜中听雪的博客-CSDN博客
package com.nowcoder.community.config; import com.nowcoder.community.dao.DiscussPostMapper; import com.nowcoder.community.dao.elasticsearch.DiscussPostRepository; import org.elasticsearch.action.admin.indices.delete.DeleteIndexRequest; import org.elasticsearch.action.support.master.AcknowledgedResponse; import org.elasticsearch.client.RequestOptions; import org.elasticsearch.client.RestHighLevelClient; import org.elasticsearch.client.indices.CreateIndexRequest; import org.elasticsearch.client.indices.CreateIndexResponse; import org.elasticsearch.client.indices.GetIndexRequest; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.beans.factory.annotation.Value; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.data.elasticsearch.client.ClientConfiguration; import org.springframework.data.elasticsearch.client.RestClients; import javax.annotation.PostConstruct; import javax.annotation.PreDestroy; import java.io.IOException; @Configuration public class EsConfig { @Value("${elasticSearch.url}") private String esUrl; @Value("${elasticsearch.indices}") String esIndices; @Autowired private DiscussPostMapper discussMapper; @Autowired private DiscussPostRepository discussRepository; @Qualifier("client") @Autowired private RestHighLevelClient restHighLevelClient; //localhost:9200 写在配置文件中就可以了 @Bean RestHighLevelClient client() { ClientConfiguration clientConfiguration = ClientConfiguration.builder() .connectedTo(esUrl)//elasticsearch地址 .build(); return RestClients.create(clientConfiguration).rest(); } @PostConstruct public void init() throws Exception { client(); //建立表 if(!existsIndex(esIndices)){ //createIndex(esIndices); }else{ deleteIndex(esIndices); } //把所有帖子(List<DiscussPost>)存入es的discusspost索引(es的索引相当于数据库的表) //这个插入顺序是按"最新/热门"来插入都无所谓,因为搜索的时候,会在那里按照"热门"来搜索数据。 discussRepository.saveAll(discussMapper.selectAllDiscussPosts()); } @PreDestroy public void destroy() throws IOException { //删除表中数据,销毁表 deleteIndex(esIndices); } //判断索引是否存在 public boolean existsIndex(String index) throws IOException { GetIndexRequest request = new GetIndexRequest(index); boolean exists = restHighLevelClient.indices().exists(request, RequestOptions.DEFAULT); return exists; } //创建索引 public boolean createIndex(String index) throws IOException { CreateIndexRequest request = new CreateIndexRequest(index); CreateIndexResponse createIndexResponse = restHighLevelClient.indices().create(request, RequestOptions.DEFAULT); return createIndexResponse.isAcknowledged(); } //删除索引 public boolean deleteIndex(String index) throws IOException { DeleteIndexRequest deleteIndexRequest = new DeleteIndexRequest(index); AcknowledgedResponse response = restHighLevelClient.indices().delete(deleteIndexRequest, RequestOptions.DEFAULT); return response.isAcknowledged(); } }
2、在pom.xml文件中添加
<plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-resources-plugin</artifactId> <version>3.1.0</version> </plugin>
遇到的错误和解决:
1、Maven编译打包项目报错:Failed to execute goal org.apache.maven.plugins:maven-resources-plugin:3.2.0:resources
用命令mvn clean package -Dmaven.test.skip=true
通过服务器上的maven把项目编译打包时报错:
[ERROR] Failed to execute goal org.apache.maven.plugins:maven-resources-plugin:3.2.0:resources (default-resources) on project community: Input length = 1 -> [Help 1]
解决:maven打包错误: Failed to execute goal org.apache.maven.plugins:maven-resources-plugin:3.2.0:resources_夜中听雪的博客-CSDN博客
即:在pom.xml文件中添加
<plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-resources-plugin</artifactId> <version>3.1.0</version> </plugin>
2、Tomcat启动时的启动日志中的报错:Caused by: java.net.BindException: Address already in use
启动时tomcat的/www/server/tomcat/logs/catalina.2021-05-16.log
产生很多日志,可能有多个SEVERE
,从最下面的一条SEVERE
开始解决,一条条往上解决。
即一直向下翻找到最后一个Caused by
,解决了这个Caused by
,再去解决上一个Caused by
。为什么要找最后一个Caused by
:,打个比方:拆线的时候,找到线头才好拆。
下方列出最下方的SEVERE
先解决它:
16-May-2021 23:56:01.330 SEVERE [main] org.apache.catalina.util.LifecycleBase.handleSubClassException Failed to initialize component [Connector[AJP/1.3-8009]] org.apache.catalina.LifecycleException: Protocol handler initialization failed at org.apache.catalina.connector.Connector.initInternal(Connector.java:942) at org.apache.catalina.util.LifecycleBase.init(LifecycleBase.java:136) at org.apache.catalina.core.StandardService.initInternal(StandardService.java:530) at org.apache.catalina.util.LifecycleBase.init(LifecycleBase.java:136) at org.apache.catalina.core.StandardServer.initInternal(StandardServer.java:875) at org.apache.catalina.util.LifecycleBase.init(LifecycleBase.java:136) at org.apache.catalina.startup.Catalina.load(Catalina.java:606) at org.apache.catalina.startup.Catalina.load(Catalina.java:629) at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) at java.lang.reflect.Method.invoke(Method.java:498) at org.apache.catalina.startup.Bootstrap.load(Bootstrap.java:311) at org.apache.catalina.startup.Bootstrap.main(Bootstrap.java:494) Caused by: java.net.BindException: Address already in use at sun.nio.ch.Net.bind0(Native Method) at sun.nio.ch.Net.bind(Net.java:444) at sun.nio.ch.Net.bind(Net.java:436) at sun.nio.ch.ServerSocketChannelImpl.bind(ServerSocketChannelImpl.java:225) at sun.nio.ch.ServerSocketAdaptor.bind(ServerSocketAdaptor.java:74) at org.apache.tomcat.util.net.NioEndpoint.bind(NioEndpoint.java:206) at org.apache.tomcat.util.net.AbstractEndpoint.init(AbstractEndpoint.java:952) at org.apache.coyote.AbstractProtocol.init(AbstractProtocol.java:550) at org.apache.catalina.connector.Connector.initInternal(Connector.java:939) ... 13 more
知识点:
netstat和lsof看端口的区别_lu123535884的专栏-CSDN博客
每天一个linux命令(51):lsof命令 - peida - 博客园
每天一个linux命令(56):netstat命令 - peida - 博客园
[root@wu1 ~]# netstat -anonetstat -ano # 查看端口使用情况 [root@wu1 ~]# netstat -ano|grep 8080 # 查看8080端口号是否已经被占用,如果结果为空则说明没有被使用,如果有值则说明已经被使用 tcp 0 0 0.0.0.0:8080 0.0.0.0:* LISTEN off (0.00/0/0) [root@wu1 ~]# lsof -i tcp:8080 COMMAND PID USER FD TYPE DEVICE SIZE/OFF NODE NAME jsvc 7922 www 50u IPv4 5287264 0t0 TCP *:webcache (LISTEN) [root@wu1 ~]# shutdown.sh [root@wu1 ~]# kill 7922 [root@wu1 ~]# startup.sh [root@wu1 ~]# lsof -i tcp:8080 COMMAND PID USER FD TYPE DEVICE SIZE/OFF NODE NAME java 20064 root 51u IPv4 57463225 0t0 TCP *:webcache (LISTEN)
然后退出,然后删除了/www/server/tomcat/webapps目录下除了ROOT.war以外的其他文件。
此时tomcat产生的日志:
# 退出:shutdown.sh 17-May-2021 09:16:06.752 INFO [main] org.apache.catalina.core.StandardServer.await A valid shutdown command was received via the shutdown port. Stopping the Server instance. 17-May-2021 09:16:06.752 INFO [main] org.apache.coyote.AbstractProtocol.pause Pausing ProtocolHandler ["http-nio-8080"] 17-May-2021 09:16:06.803 INFO [main] org.apache.coyote.AbstractProtocol.pause Pausing ProtocolHandler ["ajp-nio-8009"] 17-May-2021 09:16:06.854 INFO [main] org.apache.catalina.core.StandardService.stopInternal Stopping service Catalina 17-May-2021 09:16:07.067 WARNING [main] org.apache.catalina.loader.WebappClassLoaderBase.clearReferencesThreads The web application [ROOT] appears to have started a thread named [mysql-cj-abandoned-connection-cleanup] but has failed to stop it. This is very likely to create a memory leak. Stack trace of thread: java.lang.Object.wait(Native Method) java.lang.ref.ReferenceQueue.remove(ReferenceQueue.java:144) com.mysql.cj.jdbc.AbandonedConnectionCleanupThread.run(AbandonedConnectionCleanupThread.java:85) java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149) java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624) java.lang.Thread.run(Thread.java:748) 17-May-2021 09:16:07.083 INFO [main] org.apache.coyote.AbstractProtocol.stop Stopping ProtocolHandler ["http-nio-8080"] 17-May-2021 09:16:07.085 INFO [main] org.apache.coyote.AbstractProtocol.stop Stopping ProtocolHandler ["ajp-nio-8009"] 17-May-2021 09:16:07.087 INFO [main] org.apache.coyote.AbstractProtocol.destroy Destroying ProtocolHandler ["http-nio-8080"] 17-May-2021 09:16:07.087 INFO [main] org.apache.coyote.AbstractProtocol.destroy Destroying ProtocolHandler ["ajp-nio-8009"] 17-May-2021 09:16:08.014 INFO [mysql-cj-abandoned-connection-cleanup] org.apache.catalina.loader.WebappClassLoaderBase.checkStateForResourceLoading Illegal access: this web application instance has been stopped already. Could not load []. The following stack trace is thrown for debugging purposes as well as to attempt to terminate the thread which caused the illegal access. java.lang.IllegalStateException: Illegal access: this web application instance has been stopped already. Could not load []. The following stack trace is thrown for debugging purposes as well as to attempt to terminate the thread which caused the illegal access. at org.apache.catalina.loader.WebappClassLoaderBase.checkStateForResourceLoading(WebappClassLoaderBase.java:1295) at org.apache.catalina.loader.WebappClassLoaderBase.getResource(WebappClassLoaderBase.java:976) at com.mysql.cj.jdbc.AbandonedConnectionCleanupThread.checkThreadContextClassLoader(AbandonedConnectionCleanupThread.java:117) at com.mysql.cj.jdbc.AbandonedConnectionCleanupThread.run(AbandonedConnectionCleanupThread.java:84) at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149) at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624) at java.lang.Thread.run(Thread.java:748) # 启动:startup.sh 17-May-2021 09:19:32.309 INFO [main] org.apache.catalina.startup.VersionLoggerListener.log Server version: Apache Tomcat/9.0.0.M18 17-May-2021 09:19:32.336 INFO [main] org.apache.catalina.startup.VersionLoggerListener.log Server built: Mar 8 2017 15:20:57 UTC 17-May-2021 09:19:32.337 INFO [main] org.apache.catalina.startup.VersionLoggerListener.log Server number: 9.0.0.0 17-May-2021 09:19:32.337 INFO [main] org.apache.catalina.startup.VersionLoggerListener.log OS Name: Linux 17-May-2021 09:19:32.337 INFO [main] org.apache.catalina.startup.VersionLoggerListener.log OS Version: 3.10.0-1062.18.1.el7.x86_64 17-May-2021 09:19:32.337 INFO [main] org.apache.catalina.startup.VersionLoggerListener.log Architecture: amd64 17-May-2021 09:19:32.337 INFO [main] org.apache.catalina.startup.VersionLoggerListener.log Java Home: /usr/java/jdk1.8.0_281-amd64/jre 17-May-2021 09:19:32.337 INFO [main] org.apache.catalina.startup.VersionLoggerListener.log JVM Version: 1.8.0_281-b09 17-May-2021 09:19:32.337 INFO [main] org.apache.catalina.startup.VersionLoggerListener.log JVM Vendor: Oracle Corporation 17-May-2021 09:19:32.337 INFO [main] org.apache.catalina.startup.VersionLoggerListener.log CATALINA_BASE: /www/server/tomcat 17-May-2021 09:19:32.337 INFO [main] org.apache.catalina.startup.VersionLoggerListener.log CATALINA_HOME: /www/server/tomcat 17-May-2021 09:19:32.337 INFO [main] org.apache.catalina.startup.VersionLoggerListener.log Command line argument: -Djava.util.logging.config.file=/www/server/tomcat/conf/logging.properties 17-May-2021 09:19:32.337 INFO [main] org.apache.catalina.startup.VersionLoggerListener.log Command line argument: -Djava.util.logging.manager=org.apache.juli.ClassLoaderLogManager 17-May-2021 09:19:32.337 INFO [main] org.apache.catalina.startup.VersionLoggerListener.log Command line argument: -Djdk.tls.ephemeralDHKeySize=2048 17-May-2021 09:19:32.338 INFO [main] org.apache.catalina.startup.VersionLoggerListener.log Command line argument: -Djava.protocol.handler.pkgs=org.apache.catalina.webresources 17-May-2021 09:19:32.338 INFO [main] org.apache.catalina.startup.VersionLoggerListener.log Command line argument: -Dcatalina.base=/www/server/tomcat 17-May-2021 09:19:32.339 INFO [main] org.apache.catalina.startup.VersionLoggerListener.log Command line argument: -Dcatalina.home=/www/server/tomcat 17-May-2021 09:19:32.339 INFO [main] org.apache.catalina.startup.VersionLoggerListener.log Command line argument: -Djava.io.tmpdir=/www/server/tomcat/temp 17-May-2021 09:19:32.339 INFO [main] org.apache.catalina.core.AprLifecycleListener.lifecycleEvent The APR based Apache Tomcat Native library which allows optimal performance in production environments was not found on the java.library.path: /usr/java/packages/lib/amd64:/usr/lib64:/lib64:/lib:/usr/lib 17-May-2021 09:19:32.534 INFO [main] org.apache.coyote.AbstractProtocol.init Initializing ProtocolHandler ["http-nio-8080"] 17-May-2021 09:19:32.558 INFO [main] org.apache.tomcat.util.net.NioSelectorPool.getSharedSelector Using a shared selector for servlet write/read 17-May-2021 09:19:32.560 INFO [main] org.apache.coyote.AbstractProtocol.init Initializing ProtocolHandler ["ajp-nio-8009"] 17-May-2021 09:19:32.561 INFO [main] org.apache.tomcat.util.net.NioSelectorPool.getSharedSelector Using a shared selector for servlet write/read 17-May-2021 09:19:32.562 INFO [main] org.apache.catalina.startup.Catalina.load Initialization processed in 728 ms 17-May-2021 09:19:32.582 INFO [main] org.apache.catalina.core.StandardService.startInternal Starting service Catalina 17-May-2021 09:19:32.582 INFO [main] org.apache.catalina.core.StandardEngine.startInternal Starting Servlet Engine: Apache Tomcat/9.0.0.M18 17-May-2021 09:19:32.610 INFO [main] org.apache.catalina.startup.HostConfig.deployWAR Deploying web application archive /www/server/tomcat/webapps/ROOT.war 17-May-2021 09:19:37.690 INFO [main] org.apache.jasper.servlet.TldScanner.scanJars At least one JAR was scanned for TLDs yet contained no TLDs. Enable debug logging for this logger for a complete list of JARs that were scanned but no TLDs were found in them. Skipping unneeded JARs during scanning can improve startup time and JSP compilation time. 17-May-2021 09:19:50.891 INFO [main] org.apache.catalina.startup.HostConfig.deployWAR Deployment of web application archive /www/server/tomcat/webapps/ROOT.war has finished in 18,277 ms 17-May-2021 09:19:50.895 INFO [main] org.apache.coyote.AbstractProtocol.start Starting ProtocolHandler [http-nio-8080] 17-May-2021 09:19:50.978 INFO [main] org.apache.coyote.AbstractProtocol.start Starting ProtocolHandler [ajp-nio-8009] 17-May-2021 09:19:50.983 INFO [main] org.apache.catalina.startup.Catalina.start Server startup in 18420 ms # 启动后
可以从上面的日志看出Caused by: java.net.BindException: Address already in use
没有了。
3、/tmp/community/log_error.log
日志中关于Kafka的报错:Exception thrown when sending a message with key=‘null’
此时项目是可以通过ip地址访问到的,发现点赞时需要通过刷新才能看到点赞成功,说明redis没有问题,但是Kafka有问题。
此时,/tmp/community
下,原先的错误日志太多,分不出是哪个错误。
于是可以:
方案1、删除所有/tmp/community
下的日志,然后关闭tomcat再启动tomcat(因为删除日志后,不重新启动tomcat,那么无论你在ip地址访问到的项目上做什么,都不会有日志/tmp/community
。),再次测试点赞,查看/tmp/community/log_error.log
日志。
或者
方案2:关闭tomcat再启动tomcat,然后在/tmp/community/log_error.log
下的原先的错误日志下做分割线,然后再次测试点赞,在宝塔面板的文本编辑器里刷新/tmp/community/log_error.log
日志。
下方是点赞后,/tmp/community/log_error.log
日志里的报错:
2021-05-17 12:16:52,666 ERROR [http-nio-8080-exec-2] o.s.k.s.LoggingProducerListener [LogAccessor.java:261] Exception thrown when sending a message with key='null' and payload='{"data":{"postId":277},"entityId":277,"entityType":1,"entityUserId":149,"topic":"like","userId":111}' to topic like: org.apache.kafka.common.errors.TimeoutException: Topic like not present in metadata after 60000 ms. 2021-05-17 12:16:52,669 ERROR [http-nio-8080-exec-2] c.n.c.c.a.ExceptionAdvice
解决:服务器上Kafka启动报错:error=‘Cannot allocate memory‘ (errno=12)_夜中听雪的博客-CSDN博客
4、服务器上的MySQL启动失败:Starting MySQL…The server quit without updating PID file
服务器上的MySQL启动失败:Starting MySQL…The server quit without updating PID file_夜中听雪的博客-CSDN博客
5、重启Linux服务器上的elasticsearch时,需要做的步骤
重启Linux服务器上的elasticsearch时,需要做的步骤_夜中听雪的博客-CSDN博客
8.4、项目总结
图中的下方三行是基石。
原图中带下划线的和带@的内容是重点内容。
算法:前缀树过滤敏感词。
数据结构:Redis的数据结构。Redis有许多种数据结构,每种数据结构适合解决什么样的问题,适合缓存什么样的数据。
Kafka:重点是生产者与消费者模式,只有你理解了,才能明白什么时候用哪些功能来解决什么问题。
ElasticSearch:重点是它的数据结构,以索引(表)方式来存。建议找文章自己学习ES的索引。
Caffeine:本地缓存,有一定局限性,把它和Redis一起回顾,因为它们都是缓存。
从运维角度来讲整个项目(就是分布式部署)
静态资源(图片)和动态资源(controller)是部署在两个服务器上的。比如:牛客网的是在域名nowcoder.com
上,牛客网的图片是在static.nowcoder.com
上,这两个是不同的域名,会对应到两个不同的服务器。
客户端找nginx请求动态资源,找CDN请求静态资源。
- nginx:能对服务器做反向代理,如果你有多个服务器,它能对服务器做负载均衡。nginx会主从备份,即有两台服务器,一台处理客户端请求,一台只是备份。
- CDN:把你的资源部署到各地的多个服务器上,用户访问网站时,会从最近的服务器加载资源。
有多台服务器,nginx会把客户端请求发送到某一台服务器,每台服务器中都有项目community和本地缓存。
数据库通常要做读写分离的,一台数据库复制读,一台数据库负责写。负责写的数据库在写入数据以后,会把数据同步到负责读取的数据库里。
为什么Redis、Kafka、ElasticSearch都是部署多个,但是数据库却只进行主从备份?因为数据库部署和它们一样做集群式部署的话的话,那么就要处理分布式事务,这个比较麻烦,所以我们一般尽量避免这种情况。而且,一般的业务也达不到要部署多个数据库,因为在访问数据库前,会先访问本地缓存,再访问Redis,最后都没有才访问数据库。
我们用的文件服务器是七牛云。
面试官关注的点:性能、可靠性、安全。
老师:面试官面试你看什么?
1、职业素养,看基本功。看数据结构、算法、基础。看你大学学没学。
2、项目经验。你的技术栈全不全,进来了能不能直接工作。你能直接工作就不需要找人带你,找人带你,你会拖带你的那人
的后腿,带你的人工作效率就低了。
3、有多个入围者,他会看你长板,而不是短板。看你最擅长的领域是什么水平,看你的钻研能力、独立解决问题的能力。所以面试官会让你说你哪里熟,他就问你哪里,挖到你的底。建议的几个深入研究方面,任选一个:Redis、数据库读写分离、Nginx、Spring源码、Spring Security、本地缓存、Tomcat。
8.5、常见面试题
悲观锁:不允许出问题。
乐观锁:出问题了我再去解决。
更新数据很频繁,用悲观锁。
更新数据不频繁,查询数据多,用乐观锁。
数据库中,事务是为了保证安全,索引是为了提高效率。
Interceptor拦截器的三个方法:preHandle()、postHandle()、afterCompletion()。
客户端发出请求。
- DispatcherServlet:核心。客户端发出的请求由它来处理,它调用一系列组件来解决该请求。
- HandlerMapping:根据客户端访问路径找到其对应的Controller。
- HandlerExecutionChain:封装了:1、解决该请求的Controller,2、对该请求实现拦截的拦截器。它把这两样交给了DispatcherServlet。
- HandlerAdapter:从DispatcherServlet得到Controller并调用。
- ModelAndView:由Controller返回ModelAndView给DispatcherServlet。
- ViewResolver:从DispatcherServlet得到ModelAndView,ViewResolver会找到模板引擎,把数据给模板,就是View。
View:也叫模板引擎,它向客户端做渲染和展现。
这篇关于Java牛客项目课_仿牛客网讨论区_第八章的文章就介绍到这儿,希望我们推荐的文章对大家有所帮助,也希望大家多多支持为之网!
- 2025-01-102025 蛇年,J 人直播带货内容审核团队必备的办公软件有哪 6 款?
- 2025-01-10高效运营背后的支柱:文档管理优化指南
- 2025-01-10年末压力山大?试试优化你的文档管理
- 2025-01-10跨部门协作中的进度追踪重要性解析
- 2025-01-10总结 JavaScript 中的变体函数调用方式
- 2025-01-10HR团队如何通过数据驱动提升管理效率?6个策略
- 2025-01-10WBS实战指南:如何一步步构建高效项目管理框架?
- 2025-01-10实现精准执行:团队协作新方法
- 2025-01-10如何使用工具提升活动策划团队的工作效率?几个必备工具推荐
- 2025-01-10WiX 标签使用介绍:打造专业安装程序的利器