如何高效地架构一个Java项目
引言
Java是企业级应用开发的主流语言之一,而我们作为使用Java语言的程序员,职称有初级、中级、高级、资深、经理、架构,但我们往往只是慢慢通过经验的积累迭代了自己的等级,如果没有保持学习的习惯,大多数程序员会停留在接近高级的位置,简单来讲就是CRUD工程师,小编不甘心于此,所以长期保持学习新知识的习惯,尝试很多大于自身能力的事情,我相信未来的某一天我会感谢曾经努力的自己,下面的内容是我在尝试架构项目时总结的经验,希望能帮助到大家
前期准备
- 需求分析:明确项目的功能需求
- 技术选型:
- Java版本
- 8,17
- 框架选择
- 应用:Spring,SpringBoot,SpringCloud
- ORM(对象关系映射):JPA,MyBatis(Plus)
- 数据库选择
- 关系型:MySQL,PostgreSQL,Oracle
- 非关系型:Redis,MongoDB
- 时序数据库(物联网):TDengine,IoTDB
- 构建工具
- Maven,Gradle
- Java版本
项目结构设计
- 分层架构
- 认证授权
- 控制层
- 业务层
- 数据层
- 模块划分
- 按功能划分
- 按业务划分
简单示例
跳过项目的功能需求分析(具体项目具体分析),技术选型,Java版本选择17,应用框架选择SpringBoot,ORM(对象关系映射)框架选择MyBatis-Plus,数据库选择MySQL 8.x,构建工具选择Maven,项目结构,拦截器中完成认证授权,控制层接收用户请求调用业务层的方法,业务层处理逻辑调用数据层的方法,数据层与数据库交互,跳过模块划分(具体项目具体分析)
准备开发环境
1.下载安装配置Java17
访问官方的下载地址:Java Archive Downloads - Java SE 17
1.下载并解压
2.配置环境变量
我的电脑 -> 属性 -> 高级系统设置 -> 环境变量 ->系统变量(S) -> 新建(W)
双击系统变量(S)中的Path -> 新建(N)
确定后打开命令提示符界面(快捷键 win+R 输入 cmd 回车),输入java -version命令查看是否安装成功
2.下载安装MySQL 8.x
访问官方的下载地址:MySQL :: Download MySQL Installer (Archived Versions)
参考文章:【MySQL8.0.39下载安装】_mysql8.0.39.0安装教程-CSDN博客
架构项目
1.创建SpringBoot项目
2.创建包/文件结构
3.认证与授权
首先确定使用什么标准和框架进行认证与授权,常见的标准有:OAuth 2.0,JWT,常见的框架有:Spring Security,Apache Shiro,我采用的是近几年很火的轻量级框架:SaToken,如何集成可以参考我的另一篇文章:Java集成Sa-Token进行认证与授权_基于satoken的 sop-CSDN博客
4.创建数据库、用户表(含索引)
DROP DATABASE IF EXISTS `muze`;
CREATE DATABASE `muze` DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci;
SET NAMES utf8mb4;
SET FOREIGN_KEY_CHECKS = 0;
USE `muze`;
DROP TABLE IF EXISTS `t_user`;
CREATE TABLE `t_user` (
id BIGINT NOT NULL AUTO_INCREMENT COMMENT '主键',
username VARCHAR(30) COLLATE utf8mb4_0900_bin NOT NULL COMMENT '用户名',
password VARCHAR(255) COLLATE utf8mb4_0900_bin NOT NULL COMMENT '密码',
PRIMARY KEY (id)
) ENGINE=INNODB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci COMMENT='用户表';
CREATE INDEX idx_username ON t_user(username);
5.创建用户实体
为了方便实体类的编写,我们引入依赖 - 小辣椒
<!-- 小辣椒 -->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</dependency>
/**
* 用户实体
* @author muze
*/
@Data
@TableName("t_user")
public class User implements Serializable {
@Serial
private static final long serialVersionUID = 684552117916625567L;
/**
* 主键
*/
@TableId(type = IdType.AUTO)
private Long id;
/**
* 账号
*/
private String username;
/**
* 密码
*/
private String password;
}
6.创建用户数据层
技术选型时数据库是MySQL,ORM(对象关系映射)框架是MyBatis-Plus,因此引入对应依赖
<!-- MySQL -->
<dependency>
<groupId>com.mysql</groupId>
<artifactId>mysql-connector-j</artifactId>
<version>8.0.33</version>
</dependency>
<!-- MyBatis-Plus -->
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-boot-starter</artifactId>
<version>3.5.7</version>
</dependency>
在启动类上打MyBatis-Plus提供的@MapperScan("MyBatis Mapper 接口包路径"),自动扫描指定包下的 MyBatis Mapper 接口,并将它们注册为 Spring 容器中的 Bean
/**
* 启动类
* @author muze
*/
@MapperScan("com.muze.project.mapper")
@SpringBootApplication
public class ProjectApplication {
public static void main(String[] args) {
SpringApplication.run(ProjectApplication.class, args);
}
}
在配置文件application.yml中添加数据库连接信息
spring:
datasource:
url: jdbc:mysql://localhost:3306/muze?useSSL=false&serverTimezone=UTC&useUnicode=true&characterEncoding=utf-8
username: 你的用户名
password: 你的密码
driver-class-name: com.mysql.cj.jdbc.Driver
用户数据层
/**
* 用户数据层
* @author muze
*/
public interface UserMapper extends BaseMapper<User> {
}
7.创建用户业务层
我习惯将业务层分离为接口层和实现层,所以我会在sevice包下创建一个impl包,如果你不习惯可以只编写实现层,编写用户登录方法前需要定义方法入参和返回值
入参:请求实体(用户名 + 密码)
返回值:登录结果
创建DTO(请求实体)
/**
* 用户登录请求实体
* @author muze
*/
@Data
public class UserLoginDTO implements Serializable {
@Serial
private static final long serialVersionUID = -1706553212610156227L;
/**
* 用户名
*/
private String username;
/**
* 密码
*/
private String password;
}
用户登录业务接口层和实现层
/**
* 用户业务接口层
*/
public interface IUserService {
/**
* 登录
* @param userLoginDTO 用户登录请求实体
* @return 登录结果
*/
String login(UserLoginDTO userLoginDTO);
}
/**
* 用户业务实现层
* @author muze
*/
@Service
public class UserServiceImpl implements IUserService {
/**
* 注入用户数据层
*/
@Autowired
private UserMapper userMapper;
@Override
public String login(UserLoginDTO userLoginDTO) {
// 取出用户名和密码
String username = userLoginDTO.getUsername();
String password = userLoginDTO.getPassword();
// 构建查询条件
LambdaQueryWrapper<User> userLambdaQueryWrapper = new LambdaQueryWrapper<User>().eq(User::getUsername, username);
// 查询用户
User user = userMapper.selectOne(userLambdaQueryWrapper);
// 如果用户为空或者输入密码与用户密码不匹配则返回:用户名或密码错误
if (user == null || !password.equals(user.getPassword())) return "用户名或密码错误";
// 使用SaToken的工具类StpUtil调用登录方法login,入参:用户id
StpUtil.login(user.getId());
// 返回:登录成功
return "登录成功";
}
}
8.创建用户控制层
编写控制层前我们要先确定请求路径,请求方式,请求参数,响应数据
请求路径:/user/login
请求方式:POST
请求参数:用户名 + 密码
响应数据:响应码 + 响应消息 + 响应数据
DTO(请求实体)已经在编写用户业务层时创建好了
VO(响应实体)使用SaToken提供的SaResult
/**
* 用户控制层
*/
@RestController
@RequestMapping("/user")
public class UserLogin {
/**
* 注入用户业务接口层
*/
@Autowired
private IUserService userService;
/**
* 登录
* @param userLoginDTO 用户登录请求实体
* @return 响应码 + 响应消息 + 响应数据
*/
@PostMapping("/login")
public SaResult login(@RequestBody UserLoginDTO userLoginDTO) {
return SaResult.ok(userService.login(userLoginDTO));
}
}
测试
编写sql语句新增一条用户信息用于测试登录
INSERT INTO t_user (username, password) VALUES ("muze", "123456");
启动项目,使用接口调试工具测试登录功能
端口默认为8080
可以发现,Cookie中放入了一个令牌
到此,一个拥有基础功能:登录,认证与授权的Java项目就架构完成了,后续就是按照功能需求划分模块进行开发了,希望能对你有所帮助!
彩蛋:你肯定也发现了,密码并没有进行加密解密,虽然在HTTPS协议中Post请求会对传输数据加密,但在HTTP协议中Post请求不会对传输数据加密,因此我们还应该对数据传输进行加密,小编会在后续更新一篇与数据加密相关的文章,敬请期待