当前位置: 首页 > news >正文

微服务项目->在线oj系统(Java-Spring)----2.0

项⽬起步-后端⼯程创建

首先我们大概理清一下我们需要创建什么样的后端项目工程:

这里我们先做oj-modules和oj-common

父级项目创建

⽗⼯程pom.xml⽂件
<project xmlns="http://maven.apache.org/POM/4.0.0"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"><modelVersion>4.0.0</modelVersion><packaging>pom</packaging><modules><module>oj-modules</module><module>oj-common</module></modules><parent><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-parent</artifactId><version>3.0.1</version><relativePath/> <!-- lookup parent from repository --></parent><groupId>com.bite</groupId><artifactId>bite-oj</artifactId><version>1.0-SNAPSHOT</version><properties><maven.compiler.source>17</maven.compiler.source><maven.compiler.target>17</maven.compiler.target><spring-boot.version>3.0.1</spring-boot.version><spring-cloud-alibaba.version>2022.0.0.0-RC2</spring-cloud-alibaba.version><spring-cloud.version>2022.0.0</spring-cloud.version></properties><dependencies><!-- bootstrap 启动器 --><dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-starter-bootstrap</artifactId></dependency><dependency><groupId>org.projectlombok</groupId><artifactId>lombok</artifactId><optional>true</optional></dependency></dependencies><dependencyManagement><dependencies><!-- SpringCloud Alibaba 微服务 --><dependency><groupId>com.alibaba.cloud</groupId><artifactId>spring-cloud-alibaba-dependencies</artifactId><version>${spring-cloud-alibaba.version}</version><type>pom</type><scope>import</scope></dependency><!-- SpringCloud 微服务 --><dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-dependencies</artifactId><version>${spring-cloud.version}</version><type>pom</type><scope>import</scope></dependency><!-- SpringBoot 依赖配置 --><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-dependencies</artifactId><version>${spring-boot.version}</version><type>pom</type><scope>import</scope></dependency></dependencies></dependencyManagement></project>
创建oj-modules

• 删除oj-modules⼯程中的src⽬录,并修改pom.xml⽂件

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"><parent><artifactId>bite-oj</artifactId><groupId>com.bite</groupId><version>1.0-SNAPSHOT</version></parent><modelVersion>4.0.0</modelVersion><artifactId>oj-modules</artifactId><packaging>pom</packaging><properties><maven.compiler.source>17</maven.compiler.source><maven.compiler.target>17</maven.compiler.target></properties><dependencies><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId></dependency></dependencies></project>
创建微服务⼯程

以oj-system为例:

创建com.bite.system包。
创建启动类:

@SpringBootApplication
public class OjSystemApplication {public static void main(String[] args) {SpringApplication.run(OjSystemApplication.class, args);}
}
创建bootstrap.yml⽂件
server:port: 9201
# Spring
spring:application:# 应用名称name: oj-system

其他的几个微服务按照oj-system一样完成即可,需要注意的是,我们这里的端口号需要不同

最后:我们的oj-modules中pom.xml文件中的依赖会呈现这样的情况

项目结构如下所示:

这里的oj-common先不做解释,后面用到的时候再给大家展开来讲

依次启动微服务项目:

但是我们发现如果依次一个一个进行启动或者停止的话有点太过于慢,所以我们这里可以换个简单的方法进行:

推送代码到码云:

我们需要把我们的代码放到码云便于我们代码管理、协作开发、项目备份

1.码云上面创建空仓库

2.本地仓库推至远程仓库

这里需要我们之前学习过Git的内容了,我们这里需要在我们的Widows上面安装仓库,创建仓库:

这里推荐大佬的Git博客,她的Widows下的Git写的不错:

【Git】万字详解 Git 的原理与使用(上)-CSDN博客

因为我们已经创建了⼯程和⼀些核⼼⽂件,所以需要对上⾯给出的提⽰做出⼀定的调整
git initgit add .git commit -m "first commit"git remote add origin https://gitee.com/Ant_o_liu/bite-oj.gitgit push -u origin "master"

这里根据我们gitte上面的提示进行即可

我们直接在IDEA上面的终端执行即可

推送完成之后,我们在Gitte上面的仓库里面查看结果是否正确

MySQL

一个项目怎么可能不涉及数据库呢?这里我们需要使用的数据库是MySQL

我们博客里面使用的是云服务器上面docker的数据库,

1.拉取MySQL镜像
docker pull mysql:5.7
2.启动容器
docker run -d --name oj-mysql -p 3306:3306 -e "TZ=Asia/Shanghai" -e "MYSQL_ROOT_PASSWORD=123456" mysql:5.7

注意:我们这里的建立端口映射做的是docker和宿主机的映射,但是由于我们这里使用的是云服务器,所以我们还需要开通我们本机和云服务器的端口映射,否者后面会报错:

所以我们这里还需要一步(如果你使用的是本机的docker的话则不需要这步)

开通隧道(这个在我们之前学习Redis时候建立的隧道是一个道理)

如果这里有不清楚的,可以去了解一下我之前的Redis文章:

【redis初阶】------redis客户端(1)-CSDN博客

3.进入容器
docker exec -it 容器id bash
4.使用root登录MySQL
mysql -u root -p123456
5.在root里面创建ojtest用户
CREATE USER 'ojtest'@'%' IDENTIFIED BY '123456';
6.创建OJ项目数据库
CREATE database if NOT EXISTS `bitoj_dev` ;
7.赋予用户权力
GRANT CREATE,DROP,SELECT, INSERT, UPDATE, DELETE ON bitoj_dev.* TO
'ojtest'@'%';
8.使用ojtest用户登录
mysql -u ojtest -p123456
9.创建数据表

10.注意事项:

我们在使用Docker的时候总是会遇到各种各样的问题,比如创建的docker名字已经被占用,实例id已经被占用..........,我们这里作为初学者可以停止docker,然后再进行重启!也可以借助AI解决问题

DBServer

DBeaver 是⼀个流⾏的开源数据库管理⼯具,⽀持多种数据库,如 MySQL、PostgreSQL、SQLite、Oracle、DB2、SQL Server 等。DBeaver Community 是其社区版,可以免费使⽤,但可能不包含某些⾼级功能或插件。

官⽹:https://dbeaver.io/

配置maven
配置阿⾥云镜像地址:http://maven.aliyun.com/repository/public/

配置连接数据库

测试连接

根据我们之前所学的知识,我们要使⽤MySQL,都会借助mybatis作为数据库持久层。更便捷的操作数据库

MyBatis-plus

MyBatis-Plus(简称 MP)是⼀个 MyBatis 的增强⼯具,在 MyBatis 的基础上只做增强不做改变,为简化开发、提⾼效率⽽⽣。

为什么使用它而不是mybatis呢?

1.开发效率:从 “手写 SQL” 到 “约定大于配置”

2.复杂查询:链式调用替代 XML 拼接

3.性能优化:内置实用功能

  • 分页查询:MyBatis 需手动编写分页 SQL 或集成第三方插件;MP 内置 Page 插件,一行代码实现分页。
  • 逻辑删除:标记字段(如 deleted)自动转换为条件,查询时默认过滤已删除数据,避免物理删除风险。

4.高级功能:分布式场景支持

  • 主键生成:MyBatis 需手动实现主键策略(如 UUID、自增);MP 内置雪花算法(IdentifierGenerator),支持分布式唯一主键。

数据库连接池

借助mybatis-plus操作数据库虽然给我们提供了很⼤的便捷,但是这样⽅式操作数据库还是会存在⼀
些问题:
频繁的创建连接和销毁连接:包括TCP层的握⼿和MySQL协议握⼿,这会消耗⼤量时间。
连接数不受控制:在业务流量⾼峰期,⼤量应⽤服务器可能同时请求数据库连接,⽽数据库能够承载的连接数有限,这可能导致数据库性能降低。
连接管理困难:开发者需要⾃⾏管理数据库连接的创建、使⽤和关闭,这增加了开发的复杂性和出错的可能性
数据库连接池就是⽤来解决我们上⾯提到的这些问题,通过数据库连接池我们可以:
提供统⼀的管理:数据库连接池提供对数据库连接创建等操作的统⼀管理。
提⾼系统性能 :由于创建和销毁数据库连接需要消耗时间和系统资源,如果每次需要进⾏数据库操作时都进⾏创建和销毁连接,会极⼤地影响系统性能。⽽使⽤连接池,可以复⽤已经创建好的连接,⼤ 提⾼了系统的性能。
提⾼资源利⽤率 :连接池通过复⽤已有连接,避免了频繁创建和销毁连接带来的资源浪费,提⾼了系统资源的利⽤率。
提⾼系统稳定性数据库连接池可以有效地控制系统中并发访问数据库的连接数量,避免因并发连接数过多⽽导致数据库崩溃。同时,连接池还会定时检查连接的有效性,⾃动替换掉⽆效连接,保证了系统的稳定性。
数据库连接池的⼯作原理:
⼀般连接池会这⼏个参数配置:初始连接数、最⼤连接数、空闲时间、超时时间。
数据库连接池的⼯作原理是建⽴连接池对象,按照事先指定的参数创建初始数量的连接,对于⼀
个访问请求,直接从连接池中得到⼀个连接。如果连接池对象中没有空闲的连接,且连接数没有达到最⼤,则创建⼀个新的连接;如果达到最⼤,则设定⼀定的超时时间,来获取连接。使⽤完之后,将连接释放,并⾮真正关闭,⽽是将其放⼊空闲队列中,以备下⼀个客⼾使⽤。当连接池中的连接在指定时间内没有被再次使⽤时,连接将被回收,只保持初始连接量的连接数。

常⻅的数据库连接池:
C3P0、Druid、HikariCP。
为什么采⽤HikariCP

最重要原因:与Spring Boot集成良好

Spring Boot对HikariCP提供了良好的⽀持,可以轻松地在项⽬中集成和使
⽤。Spring Boot的⾃动配置功能可以⾃动配置HikariCP的连接池参数,简化了配置过程。

集成mybatis-plus与数据库连接池

pom.xml中引入依赖

 <dependency><groupId>com.baomidou</groupId><artifactId>mybatis-plus-spring-boot3-starter</artifactId><version>3.5.5</version></dependency><dependency><groupId>com.mysql</groupId><artifactId>mysql-connector-j</artifactId></dependency>
controller

Service

Domain

mapper

public interface TestMapper extends BaseMapper<TestDomain> {
}
连接配置
server:port: 9201
# Spring
spring:application:# 应用名称name: oj-systemdatasource:url: jdbc:mysql://localhost:3306/bitoj_dev?useUnicode=true&characterEncoding=utf8&useSSL=true&serverTimezone=GMT%2B8username: ojtestpassword: 123456hikari:minimum-idle: 5  # 最小空闲连接数maximum-pool-size: 20  # 最大连接数idle-timeout: 30000  # 空闲连接存活时间(毫秒)connection-timeout: 30000  # 连接超时时间(毫秒)# connection-test-query: SELECT 1# 说明:如果驱动支持 JDBC4.0,建议不设置此参数,默认会调用 Connection.isValid() 检查连接,更高效# keepalive-time: 0  # 多久检查一次连接的活性,默认不启用
启动类修改:
@MapperScan 是 Spring Boot 中 MyBatis 集成的⼀个注解,⽤于指定 MyBatis Mapper 接⼝所在的包路径。当 Spring Boot 应⽤程序启动时,它会扫描这个包路径下的所有接⼝,并将它们注册为MyBatis 的 Mapper。

表结构设计

drop table if exists `tb_sys_user`;
create table `tb_sys_user` (
user_id bigint (20) unsigned NOT NULL COMMENT ' ⽤⼾ id',
user_account varchar (32) DEFAULT NULL COMMENT ' ⽤⼾账号 ',
password varchar (100) DEFAULT NULL COMMENT ' ⽤⼾密码 ',
nick_name varchar (32) DEFAULT NULL COMMENT ' 昵称 ',
create_by bigint (8) NOT NULL COMMENT ' 创建⽤⼾ ',
create_time datetime NOT NULL COMMENT ' 创建时间 ',
update_by bigint (8) DEFAULT NULL COMMENT ' 更新⽤⼾ ',
update_time datetime DEFAULT NULL COMMENT ' 更新时间 ',
PRIMARY KEY (user_id),
UNIQUE KEY user_account (user_account)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='管理端⽤⼾表';
实体类
@Data
@TableName("tb_sys_user")
public class SysUser extends BaseEntity {@TableId(value = "USER_ID", type = IdType.ASSIGN_ID)//雪花算法private Long userId;private String userAccount;private String password;private Long createBy;private LocalDateTime createTime;private Long updateBy;private LocalDateTime updateTime;}
主键
为什么不使⽤⾃增id

1.数据迁移和备份

如果你需要将数据从⼀个数据库迁移到另⼀个数据库,或者备份和恢复数据,⾃增主键可能会导致问题。
2.删除和插⼊操作
如果表中存在⼤量删除和插⼊操作,⾃增主键可能会导致 ID 值的不连续。这可能会浪费存储空间,并可能导致某些应⽤程序或系统逻辑出现问题。
3.可预测性
⾃增主键的值是可预测的,因为它们总是按照递增的顺序⽣成。这可能会带来安全⻛险,例如,攻击者可能会尝试预测未来的 ID 值来插⼊恶意数据
如何处理⾃增id问题:
使用UUID或者雪花算法

为什么使用雪花算法

使⽤mybatis-plus⽀持雪花算法

代码优化

因为我们这个实体类里面的更新时间更新人,创建时间,创建人可能会被项目多次使用,所以我打算将他弄出一个公共类来存储

创建一个oj-common-core模块

然后讲那几个属性放入一个单独类BaseEntity

@Data
public class BaseEntity implements Serializable {private Long createBy;private LocalDateTime createTime;private Long updateBy;private LocalDateTime updateTime;
}

引入模块的依赖

为了方便对版本的管理,我们这里可以吧版本号统一放到bite-oj这个父项目的pom.xml里面

修改代码SysUser

@Data
@TableName("tb_sys_user")
public class SysUser extends BaseEntity {@TableId(value = "USER_ID", type = IdType.ASSIGN_ID)//雪花算法private Long userId;private String userAccount;private String password;}

代码初步开发

在开始写代码之前,我们先得有一个接口文档,来规定我们得统一结果返回,已经访问接口

统一返回结果

Data
public class R <T>{private T data;private String msg;private int code;
}

返回结果的枚举类

@AllArgsConstructor
@Getter
public enum ResultCode {//操作成功SUCCESS                         (1000, "操作成功"),//服务器内部错误,友好提示ERROR                           (2000, "服务繁忙请稍后重试"),//操作失败,但是服务器不存在异常FAILED                          (3000, "操作失败"),FAILED_UNAUTHORIZED             (3001, "未授权"),FAILED_PARAMS_VALIDATE          (3002, "参数校验失败"),FAILED_NOT_EXISTS               (3003, "资源不存在"),FAILED_ALREADY_EXISTS           (3004, "资源已存在"),FAILED_USER_EXISTS              (3101, "用户已存在"),FAILED_USER_NOT_EXISTS          (3102, "用户不存在"),FAILED_LOGIN                    (3103, "用户名或密码错误"),FAILED_USER_BANNED              (3104, "您已被列入黑名单,请联系管理员.");/*** 状态码*/private int code;/*** 状态描述*/private String msg;
}

注意:由于这里是枚举类,所以我们无法使用@Data注解,并且因为这个枚举是有参数的构造犯法,所以我们无法直接使用@Data,所以我们这里使用的是@AllArgsConstructor,但是我们从外面需要使用到get方法,所以加了一个@Getter

login接口的接受参数方式(RequestBody)

@Data
public class LoginDTO {private String userAccount;private String password;
}

Controller

@RestController
@RequestMapping("sysUser")
public class SysUserController {@Autowiredprivate ISysUserService sysUserService;@RequestMapping("login")public R<Void> login(@RequestBody LoginDTO loginDTO){return  sysUserService.login(loginDTO.getUserAccount(),loginDTO.getPassword());}
}

service


@Service
public class SysUserServiceImp implements ISysUserService{@Autowiredprivate SysUserMapper sysUserMapper;@Overridepublic R<Void> login(String userAccount, String password) {LambdaQueryWrapper<SysUser> queryWrapper=new LambdaQueryWrapper<>();SysUser sysUser=  sysUserMapper.selectOne(queryWrapper.select(SysUser::getPassword).eq(SysUser::getUserAccount,userAccount));R loginResult=new R();if(sysUser==null){loginResult.setCode(ResultCode.FAILED_USER_NOT_EXISTS.getCode());loginResult.setMsg(ResultCode.FAILED_USER_NOT_EXISTS.getMsg());return loginResult;}if(sysUser.getPassword()==password){loginResult.setCode(ResultCode.SUCCESS.getCode());loginResult.setMsg(ResultCode.SUCCESS.getMsg());return loginResult;}loginResult.setCode(ResultCode.FAILED_LOGIN.getCode());loginResult.setMsg(ResultCode.FAILED_LOGIN.getMsg());return loginResult;}
}
package com.bite.system.service.impl;import com.bite.common.core.domain.R;public interface ISysUserService {public R login(String userAccount, String password);
}

mapper

public interface SysUserMapper extends BaseMapper<SysUser> {
}

http://www.dtcms.com/a/390785.html

相关文章:

  • Swift闭包使用详情
  • STM32,新手学习
  • 保险丝Fuse
  • Kafka的持久化及副本机制总结
  • c() 函数在 R 中的用途详解
  • 使用Rsync+sersync实现数据实时同步
  • 关于conda forge长时间solving的问题以及如何解决
  • 前端学习手册-JavaScript基础语法(十)
  • 如何在 Linux 服务器上查看 GPU 型号与 CUDA 版本?
  • LeetCode hot 100 解题思路记录(三)
  • 小程序移动端设计UI(二)酒店自助入住小程序—东方仙盟练气期
  • 解决pnpm中的 Pinia 版本冲突:Cannot read properties of undefined (reading ‘_s‘)
  • 说一说大模型后训练的流程
  • 【微实验】激光测径系列(三)
  • Vim 使用从入门到精通
  • 快速实现 Excel 表格转 SVG:Java 教程
  • [极客大挑战 2019]LoveSQL
  • Excel和WPS表格中选中全部空单元格并输入相同内容
  • 日志易制造业安全UEBA解决方案
  • Java 将 HTML 转换为 Excel:实用指南
  • MySQL索引篇---数据结构的选择
  • 【STM32 CubeMX + Keil】 中断、NVIC 、EXTI
  • BIGO一面面试总结
  • Ansible-fetch模块
  • DevExpress WPF中文教程:DataGrid - 服务器数据和大型数据源
  • Vue项目不同页面显示不同的title
  • NW820NW825美光固态闪存NW829NW832
  • aosp13/14/15/16如何实现窗口局部区域高斯模糊毛玻璃效果及Winscope原生重大bug发现
  • Java微服务架构设计模式精解
  • 设计模式面试之单例模式常问知识点