IDEA实现纯java项目并打包jar的步骤(不使用Maven,Spring)
目录
- 前言
- 要素
- 搭建项目
- 逻辑
- 数据库连接
- DatabaseConnection.Java
- 表增删改查
- User.java
- UserDao.java
- 简单User处理逻辑
- ResponseResult.java
- UserService.java
- 工具类实现
- jsonUtil.java
- TimeUtil.java
- 路由逻辑
- RouteHandler.java
- RouteRegistry.java
- RequestRouter.java
- UserRouteHandler.java
- 定时任务
- BaseTask.java
- TaskScheduler.java
- UserCleanupTask.java
- 启动类
- Main.java
- 打包Jar并启动
- 启动
- 打包jar
- 项目GIT
- 优缺点
- 结语
前言
在工作的过程中,我们一直有用
又因为之前只是使用,对其原理不是很了解然后突然想到,如果要构建一个不用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.prepareSphptatement(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(); ifandroid (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 : methowww.devze.comdRoutes.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 : quepythonry.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:
at sun.nio.ch.Net.bind0(Native Method)at sun.nio.ch.Net.bind(Net.jjavascriptava: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)Address already in use
: bind
启动点击
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
等待打包完成,这个时候会在我们的
关闭我们的项目,然后启动该jar包out
文件夹下的artifacts
文件夹会看到我们刚刚打包后的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后端项目DEMO
优缺点
综上,我们已经很清晰明了的知道java是怎么去运作我们的项目了,但是还是那句话,这个只是让你更好的学习和了解java,真正要开发一个项目还是选择Maven,Spring框架,如下我列举了一些纯java项目优缺点
轻量: 启动快,内存占用第,无框架开销 自主掌控: 自主实现逻辑,可以深度理解底层机制(HTTP/TCP等)学习价值高: 对于掌握基础友好
优点
开发效率低: 手动实现路由,依赖注入等,重复造轮子,缺少标准项目结构维护成本高: 自行管理依赖版本,缺少自动化测试支持,扩展性差团队协作难: 无统一的开发规范,项目结构依赖个人风格
缺点
结语
到此这篇关于IDEA实现纯java项目并打包jar(不使用Maven,Spring)的文章就介绍到这了,更多相关DEA纯java项目打包jar内容请搜索编程客栈(www.devze.com)以前的文章或继续浏览下面的相关文章希望大家以后多多支持编程客栈(www.devze.com)!
精彩评论