前言
在工作的过程中,我们一直有用
Maven
,Spring
,SpringBoot
等去构建我们的java后端项目
又因为之前只是使用,对其原理不是很了解
然后突然想到,如果要构建一个不用Maven
,Spring
要怎么实现?
最近工作稍微清闲一点,于是有时间研究一下,最终有了这篇文章
因此,本文章最终会教你实现如下
✨ 使用JDBC连接MySql
✨ 使用纯java实现GET,POST请求供外部接口调用
✨ 实现纯java项目实现简单的定时任务
✨ 使用纯Java启动我们的项目
✨ 使用IDEA打包jar包
要素
正常来说,我们肯定是应该使用Maven,Spring等去构建我们的项目,但是
这篇文章的意义主要是为了了解纯java是如何实现一个后端系统的,为了后面的Maven,Spring构建有更深的了解
要实现一个最简单后端系统,我们首先需要可以联通我们的数据库,然后去进行增删改查,实现具体的逻辑,此外还可以添加定时任务进行点缀处理,当然如果自己的项目不涉及定时任务,这个也是可以省略
最终我实现的项目结构如下
PureJavaDemo // 项目名称
├── lib // 依赖文件夹
├── mysql-connector-java-8.0.15.jar // mysql驱动依赖文件包
├── src
├── com
├── demo
├── bean
├── vo
├── ResponseResult.java // 统一响应实体类
├── User.java // 表User的对象实体
├── config // 配置相关代码
├── router // 路由相关代码
├── RouteHandler.java // 路由处理器
├── RouteRegistry.java // 路由注册器
├── DatabaseConnection.java // mysql数据库连接配置类
├── controller // 路由控制层
├── RequestRouter.java // 请求路由器
├── UserRouteHandler.java // 表User相关逻辑请求路由
├── dao // 数据库不同表增删改查dao层
├── UserDao // User表增删改查
├── schedule // 定时任务相关逻辑代码
├── BaseTask.java // 定时任务基类
├── TaskScheduler.java // 定时任务管理器
├── UserCleanupTask.java // 用户清除定时任务
├── service // 具体逻辑实现
├── UserService.java // User相关逻辑具体实现
├── util // 工具类
├── JsonUtil.java // JSON字符处理工具类
├── TimeUtil.java // 时间处理工具类
├── Main.java // 项目启动类
我实际项目截图如下
在我实际的纯java项目中,我只引入了一个
mysql
依赖包,实际上也可以如Maven
,Spring
一样引入对应pom.xml
里面的相关依赖来精简自己的项目逻辑
搭建项目
首先我们使用IDEA新建我们的项目
🎈 File -> New -> Project… 打开创建模块面板
🎈 选择java 创建java项目,直接点击Next,别的什么都不要动
🎈 一路Next,输入项目名称,然后点击Finish即可
🎈然后会创建一个默认什么都没有的项目
🎈 接着新建一个文件夹,取名lib,名称任意,一般叫这个;找mysql的驱动依赖文件,这里可以从我们的
本地Maven库拿
,或者从网上搜索
获取mysql依赖,其他依赖同理,这里我演示如何从本地获取,前提是有下载过
我们找到我们其他Maven,Spring项目,看IDEA的MAVEN配置存放路径
🎈 File -> Setting -> 搜索Maven
🎈 然后复制路径打开文件夹,再看看我们的mysql的依赖层级,任意选择一个版本,按照自己需求,然后复制里面的jar格式的文件到自己项目的lib文件夹里面
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>8.0.15</version>
</dependency>
🎈 OK之后,我们需要把把依赖文件添加到项目里面,这里指的是让项目识别到依赖
File -> Project Structure -> Libraries
打开这里之后,点击+
号选择依赖引入,引入之后会重新在这里,然后Apply
应用就OK了
🎈 到这里搭建基本好了,然后按照我给出的项目进行建立对应的java文件代码
逻辑
那么接下来就需要正式实现我们的纯java项目,我这边以一个表为例:
CREATE TABLE `user` (
`user_id` varchar(20) NOT NULL COMMENT '用户id',
`avatar` longtext COMMENT '头像',
`user_name` varchar(50) NOT NULL COMMENT '用户名',
`password` varchar(50) NOT NULL COMMENT '密码',
`create_time` datetime DEFAULT NULL COMMENT '创建时间',
`update_time` datetime DEFAULT NULL COMMENT '更新时间',
`is_admin` varchar(1) DEFAULT 'N' COMMENT '是否为管理员',
`status` varchar(1) DEFAULT 'Y' COMMENT '是否生效',
`silence` varchar(1) DEFAULT 'N' COMMENT '是否禁言',
PRIMARY KEY (`user_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
我会实现查询接口,等项目启动之后使用POSTMAN进行调用
数据库连接
首先我们使用JDBC,连接我们的数据库
DatabaseConnection.java
package com.demo.config;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;
public class DatabaseConnection {
private static final String URL = "jdbc:mysql://localhost:3306/chat?useUnicode=true&characterEncoding=UTF-8&useSSL=false&serverTimezone=UTC";
private static final String USER = "root";
private static final String PASSWORD = "root";
static {
try {
Class.forName("com.mysql.cj.jdbc.Driver");
//Class.forName("com.mysql.cj.jdbc.Driver", true, Thread.currentThread().getContextClassLoader());
} catch (ClassNotFoundException e) {
throw new RuntimeException("MySQL JDBC Driver not found", e);
}
}
public static Connection getConnection() throws SQLException {
return DriverManager.getConnection(URL, USER, PASSWORD);
}
public static void closeConnection(Connection conn) {
if (conn != null) {
try {
conn.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
}
}
表增删改查
这个是映射User表的增删改查,通过传递数据库的连接实现增删改查,其他表的可以按照这个相同处理,同样要实现增删改查,需要把实体建立出来
User.java
package com.demo.bean;
import java.util.Date;
public class User {
private String userId;
private String avatar;
private String userName;
private String password;
private Date createTime;
private Date updateTime;
private String isAdmin;
private String status;
private String silence;
// Getters and Setters
public String getUserId() { return userId; }
public void setUserId(String userId) { this.userId = userId; }
public String getAvatar() { return avatar; }
public void setAvatar(String avatar) { this.avatar = avatar; }
public String getUserName() { return userName; }
public void setUserName(String userName) { this.userName = userName; }
public String getPassword() { return password; }
public void setPassword(String password) { this.password = password; }
public Date getCreateTime() { return createTime; }
public void setCreateTime(Date createTime) { this.createTime = createTime; }
public Date getUpdateTime() { return updateTime; }
public void setUpdateTime(Date updateTime) { this.updateTime = updateTime; }
public String getIsAdmin() { return isAdmin; }
public void setIsAdmin(String isAdmin) { this.isAdmin = isAdmin; }
public String getStatus() { return status; }
public void setStatus(String status) { this.status = status; }
public String getSilence() { return silence; }
public void setSilence(String silence) { this.silence = silence; }
@Override
public String toString() {
return "User{" +
"userId='" + userId + '\'' +
", userName='" + userName + '\'' +
", avatar='" + avatar + '\'' +
", password='" + password + '\'' +
", createTime='" + createTime + "\'" +
", updateTime='" + updateTime + "\'" +
", isAdmin='" + isAdmin + "\'" +
", status='" + status + "\'" +
", silence='" + silence + "\'" +
'}';
}
}
UserDao.java
package com.demo.dao;
import com.demo.bean.User;
import java.sql.*;
import java.util.ArrayList;
import java.util.List;
public class UserDao {
// 查询所有用户
public List<User> selectAllUsers(Connection conn) throws SQLException {
List<User> users = new ArrayList<>();
String sql = "SELECT * FROM user";
try (PreparedStatement stmt = conn.prepareStatement(sql);
ResultSet rs = stmt.executeQuery()) {
while (rs.next()) {
users.add(mapResultSetToUser(rs));
}
}
return users;
}
// 根据用户ID查询用户
public User selectUserByUserId(Connection conn, String userId) throws SQLException {
String sql = "SELECT * FROM user WHERE user_id = ?";
try (PreparedStatement stmt = conn.prepareStatement(sql)) {
stmt.setString(1, userId);
try (ResultSet rs = stmt.executeQuery()) {
if (rs.next()) {
return mapResultSetToUser(rs);
}
}
}
return null;
}
// 新增用户
public int insertUser(Connection conn, User user) throws SQLException {
String sql = "INSERT INTO user (" +
"user_id, avatar, user_name, password, " +
"create_time, update_time, is_admin, status, silence" +
") VALUES (?, ?, ?, ?, NOW(), NOW(), ?, ?, ?)";
try (PreparedStatement stmt = conn.prepareStatement(sql)) {
stmt.setString(1, user.getUserId());
stmt.setString(2, user.getAvatar());
stmt.setString(3, user.getUserName());
stmt.setString(4, user.getPassword());
stmt.setString(5, user.getIsAdmin());
stmt.setString(6, user.getStatus());
stmt.setString(7, user.getSilence());
return stmt.executeUpdate();
}
}
// 根据用户ID删除用户
public int deleteUserById(Connection conn, String userId) throws SQLException {
String sql = "DELETE FROM user WHERE user_id = ?";
try (PreparedStatement stmt = conn.prepareStatement(sql)) {
stmt.setString(1, userId);
return stmt.executeUpdate();
}
}
// 更新用户信息
public int updateUser(Connection conn, User user) throws SQLException {
String sql = "UPDATE user SET " +
"avatar = ?, " +
"user_name = ?, " +
"password = ?, " +
"update_time = NOW(), " +
"is_admin = ?, " +
"status = ?, " +
"silence = ? " +
"WHERE user_id = ?";
try (PreparedStatement stmt = conn.prepareStatement(sql)) {
stmt.setString(1, user.getAvatar());
stmt.setString(2, user.getUserName());
stmt.setString(3, user.getPassword());
stmt.setString(4, user.getIsAdmin());
stmt.setString(5, user.getStatus());
stmt.setString(6, user.getSilence());
stmt.setString(7, user.getUserId());
return stmt.executeUpdate();
}
}
// 清理不活跃用户
public int deleteInactiveUsers(Connection conn, int inactiveDays) throws SQLException {
String sql = "DELETE FROM user WHERE status = 'N' AND create_time < DATE_SUB(NOW(), INTERVAL ? DAY)";
try (PreparedStatement stmt = conn.prepareStatement(sql)) {
stmt.setInt(1, inactiveDays);
return stmt.executeUpdate();
}
}
// 辅助方法:将ResultSet映射到User对象
private User mapResultSetToUser(ResultSet rs) throws SQLException {
User user = new User();
user.setUserId(rs.getString("user_id"));
user.setUserName(rs.getString("user_name"));
user.setAvatar(rs.getString("avatar"));
user.setPassword(rs.getString("password"));
user.setCreateTime(rs.getTimestamp("create_time"));
user.setUpdateTime(rs.getTimestamp("update_time"));
user.setIsAdmin(rs.getString("is_admin"));
user.setStatus(rs.getString("status"));
user.setSilence(rs.getString("silence"));
return user;
}
}
简单User处理逻辑
在这里我使用了简单的统一响应类,去返回响应结果,相关代码是
ResponseResult.java
package com.demo.bean.vo;
public class ResponseResult {
private int code;
private String message;
private Object data;
public ResponseResult(int code, String message, Object data) {
this.code = code;
this.message = message;
this.data = data;
}
public int getCode() { return code; }
public String getMessage() { return message; }
public Object getData() { return data; }
}
UserService.java
package com.demo.service;
import com.demo.bean.User;
import com.demo.bean.vo.ResponseResult;
import com.demo.config.DatabaseConnection;
import com.demo.dao.UserDao;
import java.sql.Connection;
import java.util.List;
public class UserService {
private final UserDao userDao = new UserDao();
public ResponseResult getAllUsers() {
try (Connection conn = DatabaseConnection.getConnection()) {
List<User> users = userDao.selectAllUsers(conn);
return new ResponseResult(200, "Success", users);
} catch (Exception e) {
return new ResponseResult(500, "Error: " + e.getMessage(), null);
}
}
public ResponseResult getUserById(String userId) {
try (Connection conn = DatabaseConnection.getConnection()) {
User user = userDao.selectUserByUserId(conn, userId);
if (user != null) {
return new ResponseResult(200, "Success", user);
}
return new ResponseResult(404, "User not found", null);
} catch (Exception e) {
return new ResponseResult(500, "Error: " + e.getMessage(), null);
}
}
}
工具类实现
因为为了尽可能减少引入依赖,我这边添加了工具类进行补充,实际可以添加更多依赖代替
JsonUtil.java
package com.demo.util;
import java.lang.reflect.Field;
import java.text.SimpleDateFormat;
import java.util.Collection;
import java.util.Date;
public class JsonUtil {
private static final SimpleDateFormat DATE_FORMAT = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
public static String toJson(Object obj) {
if (obj == null) return "null";
if (obj instanceof Collection) {
return collectionToJson((Collection<?>) obj);
} else if (obj instanceof String) {
return "\"" + escapeJson((String) obj) + "\"";
} else if (obj instanceof Number || obj instanceof Boolean) {
return obj.toString();
} else if (obj instanceof Date) {
return "\"" + DATE_FORMAT.format((Date) obj) + "\"";
} else {
return objectToJson(obj);
}
}
private static String objectToJson(Object obj) {
StringBuilder sb = new StringBuilder("{");
Field[] fields = obj.getClass().getDeclaredFields();
boolean firstField = true;
for (Field field : fields) {
field.setAccessible(true);
try {
Object value = field.get(obj);
if (value == null) continue;
if (!firstField) {
sb.append(",");
}
firstField = false;
sb.append("\"").append(field.getName()).append("\":");
if (value instanceof String || value instanceof Date) {
sb.append("\"").append(escapeJson(value.toString())).append("\"");
} else if (value instanceof Number || value instanceof Boolean) {
sb.append(value);
} else {
sb.append(toJson(value));
}
} catch (IllegalAccessException e) {
// 忽略无法访问的字段
}
}
return sb.append("}").toString();
}
private static String collectionToJson(Collection<?> collection) {
StringBuilder sb = new StringBuilder("[");
boolean firstElement = true;
for (Object item : collection) {
if (!firstElement) {
sb.append(",");
}
firstElement = false;
sb.append(toJson(item));
}
return sb.append("]").toString();
}
private static String escapeJson(String input) {
if (input == null) return "";
return input.replace("\\", "\\\\")
.replace("\"", "\\\"")
.replace("\b", "\\b")
.replace("\f", "\\f")
.replace("\n", "\\n")
.replace("\r", "\\r")
.replace("\t", "\\t");
}
}
TimeUtil.java
package com.demo.util;
public class TimeUtil {
/**
* 计算距离下一个指定时间点的延迟时间
* @param hour 小时 (0-23)
* @param minute 分钟 (0-59)
* @return 延迟毫秒数
*/
public static long calculateInitialDelay(int hour, int minute) {
long now = System.currentTimeMillis();
long next = java.time.LocalDate.now()
.atTime(hour, minute)
.atZone(java.time.ZoneId.systemDefault())
.toInstant()
.toEpochMilli();
if (now > next) {
next += 24 * 60 * 60 * 1000; // 如果今天的时间已过,则计算明天的时间
}
return next - now;
}
}
路由逻辑
这里路由指我们需要提供给外部访问的接口路径
RouteHandler.java
package com.demo.config.router;
import com.demo.bean.vo.ResponseResult;
import java.util.Map;
public interface RouteHandler {
ResponseResult handle(Map<String, String> params) throws Exception;
}
RouteRegistry.java
package com.demo.config.router;
import com.sun.net.httpserver.HttpExchange;
import java.util.HashMap;
import java.util.Map;
public class RouteRegistry {
private final Map<String, Map<String, RouteHandler>> routes = new HashMap<>();
public void register(String method, String path, RouteHandler handler) {
routes.computeIfAbsent(method, k -> new HashMap<>()).put(path, handler);
}
public RouteHandler findHandler(HttpExchange exchange) {
String method = exchange.getRequestMethod();
String path = exchange.getRequestURI().getPath();
Map<String, RouteHandler> methodRoutes = routes.get(method);
if (methodRoutes == null) {
return null;
}
// 精确匹配
RouteHandler handler = methodRoutes.get(path);
if (handler != null) {
return handler;
}
// 通配符匹配 (可选)
for (Map.Entry<String, RouteHandler> entry : methodRoutes.entrySet()) {
if (path.matches(entry.getKey().replace("*", ".*"))) {
return entry.getValue();
}
}
return null;
}
}
RequestRouter.java
package com.demo.controller;
import com.demo.bean.vo.ResponseResult;
import com.demo.config.router.RouteHandler;
import com.demo.config.router.RouteRegistry;
import com.demo.util.JsonUtil;
import com.sun.net.httpserver.HttpExchange;
import com.sun.net.httpserver.HttpHandler;
import java.io.IOException;
import java.io.OutputStream;
import java.net.URI;
import java.util.HashMap;
import java.util.Map;
public class RequestRouter implements HttpHandler {
private final RouteRegistry routeRegistry;
public RequestRouter() {
this.routeRegistry = new RouteRegistry();
registerRoutes();
}
private void registerRoutes() {
UserRouteHandler userHandler = new UserRouteHandler();
// 注册用户相关路由
routeRegistry.register("GET", "/user/selectAllUsers", userHandler::getAllUsers);
routeRegistry.register("GET", "/user/selectUserByUserId", userHandler::getUserById);
// 示例:注册其他路由
// routeRegistry.register("POST", "/product/create", productHandler::createProduct);
}
@Override
public void handle(HttpExchange exchange) throws IOException {
URI uri = exchange.getRequestURI();
Map<String, String> params = parseQueryParams(uri.getQuery());
ResponseResult result;
try {
RouteHandler handler = routeRegistry.findHandler(exchange);
if (handler != null) {
result = handler.handle(params);
} else {
result = new ResponseResult(404, "Endpoint not found: " + uri.getPath(), null);
}
} catch (Exception e) {
result = new ResponseResult(500, "Internal error: " + e.getMessage(), null);
e.printStackTrace();
}
sendResponse(exchange, result);
}
private void sendResponse(HttpExchange exchange, ResponseResult result) throws IOException {
String response = JsonUtil.toJson(result);
exchange.getResponseHeaders().add("Content-Type", "application/json");
exchange.sendResponseHeaders(result.getCode(), response.getBytes().length);
try (OutputStream os = exchange.getResponseBody()) {
os.write(response.getBytes());
}
}
private Map<String, String> parseQueryParams(String query) {
Map<String, String> params = new HashMap<>();
if (query != null) {
for (String param : query.split("&")) {
String[] pair = param.split("=");
if (pair.length > 1) {
params.put(pair[0], pair[1]);
}
}
}
return params;
}
}
UserRouteHandler.java
package com.demo.controller;
import com.demo.bean.vo.ResponseResult;
import com.demo.service.UserService;
import java.util.Map;
public class UserRouteHandler {
private final UserService userService = new UserService();
public ResponseResult getAllUsers(Map<String, String> params) throws Exception {
return userService.getAllUsers();
}
public ResponseResult getUserById(Map<String, String> params) throws Exception {
String userId = params.getOrDefault("userId", "");
if (!userId.isEmpty()) {
return userService.getUserById(userId);
} else {
return new ResponseResult(400, "Missing userId parameter", null);
}
}
// 添加更多用户相关的方法
// public ResponseResult createUser(Map<String, String> params) { ... }
}
定时任务
如果不加上定时任务,纯java项目是可以更精简一点,属于可有可无的,但是正常实际项目都会有定时功能的需求,因此还是加上
BaseTask.java
package com.demo.schedule;
public abstract class BaseTask implements Runnable {
protected final String taskName;
public BaseTask(String taskName) {
this.taskName = taskName;
}
@Override
public void run() {
try {
System.out.println("[" + taskName + "] 任务开始执行...");
executeTask();
System.out.println("[" + taskName + "] 任务执行完成");
} catch (Exception e) {
System.err.println("[" + taskName + "] 任务执行失败: " + e.getMessage());
e.printStackTrace();
}
}
protected abstract void executeTask() throws Exception;
public String getTaskName() {
return taskName;
}
}
TaskScheduler.java
package com.demo.schedule;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.ScheduledFuture;
import java.util.concurrent.TimeUnit;
public class TaskScheduler {
private static final ScheduledExecutorService scheduler = Executors.newScheduledThreadPool(3);
private static final TaskScheduler instance = new TaskScheduler();
private TaskScheduler() {
// 私有构造器
}
public static TaskScheduler getInstance() {
return instance;
}
/**
* 安排定时任务
* @param task 要执行的任务
* @param initialDelay 首次执行延迟时间
* @param period 执行周期
* @param unit 时间单位
* @return 定时任务控制器
*/
public ScheduledFuture<?> scheduleAtFixedRate(Runnable task,
long initialDelay,
long period,
TimeUnit unit) {
return scheduler.scheduleAtFixedRate(task, initialDelay, period, unit);
}
/**
* 安排延迟执行任务
* @param task 要执行的任务
* @param delay 延迟时间
* @param unit 时间单位
* @return 定时任务控制器
*/
public ScheduledFuture<?> schedule(Runnable task,
long delay,
TimeUnit unit) {
return scheduler.schedule(task, delay, unit);
}
/**
* 关闭定时任务管理器
*/
public void shutdown() {
scheduler.shutdown();
try {
if (!scheduler.awaitTermination(60, TimeUnit.SECONDS)) {
scheduler.shutdownNow();
}
} catch (InterruptedException e) {
scheduler.shutdownNow();
Thread.currentThread().interrupt();
}
}
}
UserCleanupTask.java
package com.demo.schedule;
import com.demo.dao.UserDao;
import com.demo.config.DatabaseConnection;
import java.sql.Connection;
public class UserCleanupTask extends BaseTask {
// 清理超过30天的未激活用户
private static final int INACTIVE_DAYS = 30;
public UserCleanupTask() {
super("用户清理任务");
}
@Override
protected void executeTask() throws Exception {
try (Connection conn = DatabaseConnection.getConnection()) {
UserDao userDao = new UserDao();
int deletedCount = userDao.deleteInactiveUsers(conn, INACTIVE_DAYS);
System.out.println("清理了 " + deletedCount + " 个超过 "
+ INACTIVE_DAYS + " 天未激活的用户");
}
}
}
启动类
启动类代表将整个项目进行启动,可以和我们的Maven项目,Spring项目一样,也是项目的入口
Main.java
package com.demo;
import com.demo.controller.RequestRouter;
import com.demo.schedule.TaskScheduler;
import com.demo.schedule.UserCleanupTask;
import com.demo.util.TimeUtil;
import com.sun.net.httpserver.HttpServer;
import java.io.IOException;
import java.net.InetSocketAddress;
import java.util.concurrent.ScheduledFuture;
import java.util.concurrent.TimeUnit;
public class Main {
public static void main(String[] args) throws IOException {
int port = 8082;
HttpServer server = HttpServer.create(new InetSocketAddress(port), 0);
server.createContext("/", new RequestRouter());
server.setExecutor(null);
server.start();
System.out.println("✅ Server started on port " + port);
// 初始化定时任务
initScheduledTasks();
// 添加关闭钩子,确保关闭
Runtime.getRuntime().addShutdownHook(new Thread(() -> {
System.out.println("Shutting down application...");
server.stop(0);
TaskScheduler.getInstance().shutdown();
System.out.println("Application shutdown complete");
}));
}
private static void initScheduledTasks() {
TaskScheduler scheduler = TaskScheduler.getInstance();
// 每10分钟执行一次的用户清理任务
ScheduledFuture<?> userCleanupTask = scheduler.scheduleAtFixedRate(
new UserCleanupTask(),
0, // 初始延迟(立即开始)
10, // 每10分钟
TimeUnit.MINUTES
);
// 每天凌晨2点执行的统计任务
scheduler.scheduleAtFixedRate(
() -> System.out.println("每日统计任务执行中..."),
TimeUtil.calculateInitialDelay(2, 0), // 凌晨2点
24, // 每天执行一次
TimeUnit.HOURS
);
System.out.println("定时任务初始化完成");
}
}
打包Jar并启动
启动
如上我们整个项目就处理完毕了,如果要求启动项目,那么要求我们的端口不能被占用,否则会报错:
Exception in thread “main” java.net.BindException:
Address already in use
: bind
at sun.nio.ch.Net.bind0(Native Method)
at sun.nio.ch.Net.bind(Net.java:433)
at sun.nio.ch.Net.bind(Net.java:425)
at sun.nio.ch.ServerSocketChannelImpl.bind(ServerSocketChannelImpl.java:223)
at sun.nio.ch.ServerSocketAdaptor.bind(ServerSocketAdaptor.java:74)
at sun.net.httpserver.ServerImpl.(ServerImpl.java:100)
at sun.net.httpserver.HttpServerImpl.(HttpServerImpl.java:50)
at sun.net.httpserver.DefaultHttpServerProvider.createHttpServer(DefaultHttpServerProvider.java:35)
at com.sun.net.httpserver.HttpServer.create(HttpServer.java:130)
at com.demo.Main.main(Main.java:10)
启动点击
Main.java
右键选择Run Mian.main()
或者Debug Mian.main()
启动之后控制台会打印一些数据
如我的项目会是这些
✅ Server started on port 8082
[用户清理任务] 任务开始执行…
定时任务初始化完成
清理了 0 个超过 30 天未激活的用户
[用户清理任务] 任务执行完成
在我的项目示例中我有两个外部调用接口
/user/selectAllUsers
/user/selectUserByUserId
此时我的表数据有这些:
INSERT INTO chat.`user` (user_id, avatar, user_name, password, create_time, update_time, is_admin, status, silence) VALUES('11', '11', '11', '11', '2025-07-14 00:00:00', '2025-07-14 00:00:00', 'N', 'Y', 'N');
此时调用接口:
http://localhost:8082/user/selectAllUsers
响应数据如下:
{
"code": 200,
"message": "Success",
"data": [
{
"userId": "11",
"avatar": "11",
"userName": "11",
"password": "11",
"createTime": "2025-07-14 08:00:00.0",
"updateTime": "2025-07-14 08:00:00.0",
"isAdmin": "N",
"status": "Y",
"silence": "N"
}
]
}
成功启动并且请求到了数据库表数据
打包jar
如上我们已经验证了项目正常启动,我们我们需要将其打包jar,使其可以在本机或者服务器正常部署使用
File -> Project Structure -> Artifacts
打开到这个界面,然后点击+
号,选择jar
下的from modules with dependencies
Module
会自动选择当前项目,Main Class
需要选择Main.java
,并且JAR files from dependencies
需要选择为copy to the output directory and link via mainfest
点击OK
然后Apply
就会多出一个项目名称的jar包在这里
然后点击Build -> Build Artifacts
再在新界面选择点击Build
等待打包完成,这个时候会在我们的
out
文件夹下的artifacts
文件夹会看到我们刚刚打包后的jar包
关闭我们的项目,然后启动该jar包
java -jar PureJavaDemo.jar
可以看到如上截图成功执行了jar,往user表加些数据再次请求postman验证是否可用
{
"code": 200,
"message": "Success",
"data": [
{
"userId": "11",
"avatar": "11",
"userName": "11",
"password": "11",
"createTime": "2025-07-14 08:00:00.0",
"updateTime": "2025-07-14 08:00:00.0",
"isAdmin": "N",
"status": "Y",
"silence": "N"
},
{
"userId": "22",
"avatar": "22",
"userName": "22",
"password": "22",
"createTime": "2025-07-14 08:00:00.0",
"updateTime": "2025-07-14 08:00:00.0",
"isAdmin": "N",
"status": "Y",
"silence": "N"
}
]
}
可以看到正常的访问,但是有一点需要注意,
打包之后的jar需要和依赖放在同一个文件夹下
项目GIT
优缺点
综上,我们已经很清晰明了的知道java是怎么去运作我们的项目了,但是还是那句话,这个只是让你更好的学习和了解java,真正要开发一个项目还是选择Maven,Spring框架,如下我列举了一些纯java项目优缺点
优点
🧡 轻量: 启动快,内存占用第,无框架开销
🧡 自主掌控: 自主实现逻辑,可以深度理解底层机制(HTTP/TCP等)
🧡学习价值高: 对于掌握基础友好
缺点
🖤开发效率低: 手动实现路由,依赖注入等,重复造轮子,缺少标准项目结构
🖤维护成本高: 自行管理依赖版本,缺少自动化测试支持,扩展性差
🖤团队协作难: 无统一的开发规范,项目结构依赖个人风格
结语
如上为实现纯java项目的过程和代码,如有遗漏后续补充