欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

IDEA實(shí)現(xiàn)純java項(xiàng)目并打包jar的步驟(不使用Maven,Spring)

 更新時(shí)間:2025年08月09日 09:13:44   作者:相與還  
在Java開發(fā)中我們通常會(huì)將我們的項(xiàng)目打包成可執(zhí)行的Jar包,以便于在其他環(huán)境中部署和運(yùn)行,這篇文章主要介紹了IDEA實(shí)現(xiàn)純java項(xiàng)目并打包jar(不使用Maven,Spring)的相關(guān)資料,需要的朋友可以參考下

前言

在工作的過程中,我們一直有用MavenSpring,SpringBoot等去構(gòu)建我們的java后端項(xiàng)目
又因?yàn)橹爸皇鞘褂?,?duì)其原理不是很了解
然后突然想到,如果要構(gòu)建一個(gè)不用Maven,Spring要怎么實(shí)現(xiàn)?
最近工作稍微清閑一點(diǎn),于是有時(shí)間研究一下,最終有了這篇文章

因此,本文章最終會(huì)教你實(shí)現(xiàn)如下

? 使用JDBC連接MySql
? 使用純java實(shí)現(xiàn)GET,POST請(qǐng)求供外部接口調(diào)用
? 實(shí)現(xiàn)純java項(xiàng)目實(shí)現(xiàn)簡單的定時(shí)任務(wù)
? 使用純Java啟動(dòng)我們的項(xiàng)目
? 使用IDEA打包jar包

要素

正常來說,我們肯定是應(yīng)該使用Maven,Spring等去構(gòu)建我們的項(xiàng)目,但是這篇文章的意義主要是為了了解純java是如何實(shí)現(xiàn)一個(gè)后端系統(tǒng)的,為了后面的Maven,Spring構(gòu)建有更深的了解

要實(shí)現(xiàn)一個(gè)最簡單后端系統(tǒng),我們首先需要可以聯(lián)通我們的數(shù)據(jù)庫,然后去進(jìn)行增刪改查,實(shí)現(xiàn)具體的邏輯,此外還可以添加定時(shí)任務(wù)進(jìn)行點(diǎn)綴處理,當(dāng)然如果自己的項(xiàng)目不涉及定時(shí)任務(wù),這個(gè)也是可以省略

最終我實(shí)現(xiàn)的項(xiàng)目結(jié)構(gòu)如下

PureJavaDemo  // 項(xiàng)目名稱
├── lib // 依賴文件夾
	├── mysql-connector-java-8.0.15.jar  // mysql驅(qū)動(dòng)依賴文件包
├── src
	├── com
		├── demo
			├── bean
				├── vo
					├── ResponseResult.java  // 統(tǒng)一響應(yīng)實(shí)體類
				├── User.java // 表User的對(duì)象實(shí)體
			├── config // 配置相關(guān)代碼
				├── router  // 路由相關(guān)代碼
					├── RouteHandler.java  // 路由處理器
					├── RouteRegistry.java // 路由注冊器
				├── DatabaseConnection.java // mysql數(shù)據(jù)庫連接配置類
			├── controller // 路由控制層
				├── RequestRouter.java // 請(qǐng)求路由器
				├── UserRouteHandler.java // 表User相關(guān)邏輯請(qǐng)求路由
			├── dao // 數(shù)據(jù)庫不同表增刪改查dao層
				├── UserDao // User表增刪改查
			├── schedule // 定時(shí)任務(wù)相關(guān)邏輯代碼
				├── BaseTask.java // 定時(shí)任務(wù)基類
				├── TaskScheduler.java // 定時(shí)任務(wù)管理器
				├── UserCleanupTask.java // 用戶清除定時(shí)任務(wù)
			├── service // 具體邏輯實(shí)現(xiàn)
				├── UserService.java // User相關(guān)邏輯具體實(shí)現(xiàn)
			├── util // 工具類
				├── JsonUtil.java // JSON字符處理工具類
				├── TimeUtil.java // 時(shí)間處理工具類				
			├── Main.java	// 項(xiàng)目啟動(dòng)類		

我實(shí)際項(xiàng)目截圖如下

在我實(shí)際的純java項(xiàng)目中,我只引入了一個(gè)mysql依賴包,實(shí)際上也可以如Maven,Spring一樣引入對(duì)應(yīng)pom.xml里面的相關(guān)依賴來精簡自己的項(xiàng)目邏輯

搭建項(xiàng)目

首先我們使用IDEA新建我們的項(xiàng)目

?? File -> New -> Project… 打開創(chuàng)建模塊面板

?? 選擇java 創(chuàng)建java項(xiàng)目,直接點(diǎn)擊Next,別的什么都不要?jiǎng)?/p>

?? 一路Next,輸入項(xiàng)目名稱,然后點(diǎn)擊Finish即可

??然后會(huì)創(chuàng)建一個(gè)默認(rèn)什么都沒有的項(xiàng)目

?? 接著新建一個(gè)文件夾,取名lib,名稱任意,一般叫這個(gè);找mysql的驅(qū)動(dòng)依賴文件,這里可以從我們的本地Maven庫拿,或者從網(wǎng)上搜索獲取mysql依賴,其他依賴同理,這里我演示如何從本地獲取,前提是有下載過

我們找到我們其他Maven,Spring項(xiàng)目,看IDEA的MAVEN配置存放路徑

?? File -> Setting -> 搜索Maven

?? 然后復(fù)制路徑打開文件夾,再看看我們的mysql的依賴層級(jí),任意選擇一個(gè)版本,按照自己需求,然后復(fù)制里面的jar格式的文件到自己項(xiàng)目的lib文件夾里面

        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>8.0.15</version>
        </dependency>

?? OK之后,我們需要把把依賴文件添加到項(xiàng)目里面,這里指的是讓項(xiàng)目識(shí)別到依賴
File -> Project Structure -> Libraries打開這里之后,點(diǎn)擊+號(hào)選擇依賴引入,引入之后會(huì)重新在這里,然后Apply應(yīng)用就OK了

?? 到這里搭建基本好了,然后按照我給出的項(xiàng)目進(jìn)行建立對(duì)應(yīng)的java文件代碼

邏輯

那么接下來就需要正式實(shí)現(xiàn)我們的純java項(xiàng)目,我這邊以一個(gè)表為例:

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 '創(chuàng)建時(shí)間',
  `update_time` datetime DEFAULT NULL COMMENT '更新時(shí)間',
  `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;

我會(huì)實(shí)現(xiàn)查詢接口,等項(xiàng)目啟動(dòng)之后使用POSTMAN進(jìn)行調(diào)用

數(shù)據(jù)庫連接

首先我們使用JDBC,連接我們的數(shù)據(jù)庫

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();
      }
    }
  }
}

表增刪改查

這個(gè)是映射User表的增刪改查,通過傳遞數(shù)據(jù)庫的連接實(shí)現(xiàn)增刪改查,其他表的可以按照這個(gè)相同處理,同樣要實(shí)現(xiàn)增刪改查,需要把實(shí)體建立出來

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;
  }

  // 根據(jù)用戶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();
    }
  }

  // 根據(jù)用戶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對(duì)象
  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處理邏輯

在這里我使用了簡單的統(tǒng)一響應(yīng)類,去返回響應(yīng)結(jié)果,相關(guān)代碼是

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);
    }
  }
}

工具類實(shí)現(xiàn)

因?yàn)闉榱吮M可能減少引入依賴,我這邊添加了工具類進(jìn)行補(bǔ)充,實(shí)際可以添加更多依賴代替

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 {
  /**
   * 計(jì)算距離下一個(gè)指定時(shí)間點(diǎn)的延遲時(shí)間
   * @param hour 小時(shí) (0-23)
   * @param minute 分鐘 (0-59)
   * @return 延遲毫秒數(shù)
   */
  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; // 如果今天的時(shí)間已過,則計(jì)算明天的時(shí)間
    }

    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();

    // 注冊用戶相關(guān)路由
    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);
    }
  }

  // 添加更多用戶相關(guān)的方法
  // public ResponseResult createUser(Map<String, String> params) { ... }
}

定時(shí)任務(wù)

如果不加上定時(shí)任務(wù),純java項(xiàng)目是可以更精簡一點(diǎn),屬于可有可無的,但是正常實(shí)際項(xiàng)目都會(huì)有定時(shí)功能的需求,因此還是加上

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 + "] 任務(wù)開始執(zhí)行...");
      executeTask();
      System.out.println("[" + taskName + "] 任務(wù)執(zhí)行完成");
    } catch (Exception e) {
      System.err.println("[" + taskName + "] 任務(wù)執(zhí)行失敗: " + 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() {
    // 私有構(gòu)造器
  }

  public static TaskScheduler getInstance() {
    return instance;
  }

  /**
   * 安排定時(shí)任務(wù)
   * @param task 要執(zhí)行的任務(wù)
   * @param initialDelay 首次執(zhí)行延遲時(shí)間
   * @param period 執(zhí)行周期
   * @param unit 時(shí)間單位
   * @return 定時(shí)任務(wù)控制器
   */
  public ScheduledFuture<?> scheduleAtFixedRate(Runnable task,
      long initialDelay,
      long period,
      TimeUnit unit) {
    return scheduler.scheduleAtFixedRate(task, initialDelay, period, unit);
  }

  /**
   * 安排延遲執(zhí)行任務(wù)
   * @param task 要執(zhí)行的任務(wù)
   * @param delay 延遲時(shí)間
   * @param unit 時(shí)間單位
   * @return 定時(shí)任務(wù)控制器
   */
  public ScheduledFuture<?> schedule(Runnable task,
      long delay,
      TimeUnit unit) {
    return scheduler.schedule(task, delay, unit);
  }

  /**
   * 關(guān)閉定時(shí)任務(wù)管理器
   */
  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("用戶清理任務(wù)");
  }

  @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 + " 個(gè)超過 "
          + INACTIVE_DAYS + " 天未激活的用戶");
    }
  }
}

啟動(dòng)類

啟動(dòng)類代表將整個(gè)項(xiàng)目進(jìn)行啟動(dòng),可以和我們的Maven項(xiàng)目,Spring項(xiàng)目一樣,也是項(xiàng)目的入口

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);

    // 初始化定時(shí)任務(wù)
    initScheduledTasks();

    // 添加關(guān)閉鉤子,確保關(guān)閉
    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分鐘執(zhí)行一次的用戶清理任務(wù)
    ScheduledFuture<?> userCleanupTask = scheduler.scheduleAtFixedRate(
        new UserCleanupTask(),
        0,   // 初始延遲(立即開始)
        10,  // 每10分鐘
        TimeUnit.MINUTES
    );

    // 每天凌晨2點(diǎn)執(zhí)行的統(tǒng)計(jì)任務(wù)
    scheduler.scheduleAtFixedRate(
        () -> System.out.println("每日統(tǒng)計(jì)任務(wù)執(zhí)行中..."),
        TimeUtil.calculateInitialDelay(2, 0), // 凌晨2點(diǎn)
        24, // 每天執(zhí)行一次
        TimeUnit.HOURS
    );

    System.out.println("定時(shí)任務(wù)初始化完成");
  }
}

打包Jar并啟動(dòng)

啟動(dòng)

如上我們整個(gè)項(xiàng)目就處理完畢了,如果要求啟動(dòng)項(xiàng)目,那么要求我們的端口不能被占用,否則會(huì)報(bào)錯(cuò):

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)

啟動(dòng)點(diǎn)擊Main.java 右鍵選擇Run Mian.main()或者Debug Mian.main()

啟動(dòng)之后控制臺(tái)會(huì)打印一些數(shù)據(jù)
如我的項(xiàng)目會(huì)是這些

? Server started on port 8082
[用戶清理任務(wù)] 任務(wù)開始執(zhí)行…
定時(shí)任務(wù)初始化完成
清理了 0 個(gè)超過 30 天未激活的用戶
[用戶清理任務(wù)] 任務(wù)執(zhí)行完成

在我的項(xiàng)目示例中我有兩個(gè)外部調(diào)用接口
/user/selectAllUsers
/user/selectUserByUserId
此時(shí)我的表數(shù)據(jù)有這些:

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');

此時(shí)調(diào)用接口:

http://localhost:8082/user/selectAllUsers

響應(yīng)數(shù)據(jù)如下:

{
    "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"
        }
    ]
}

成功啟動(dòng)并且請(qǐng)求到了數(shù)據(jù)庫表數(shù)據(jù)

打包jar

如上我們已經(jīng)驗(yàn)證了項(xiàng)目正常啟動(dòng),我們我們需要將其打包jar,使其可以在本機(jī)或者服務(wù)器正常部署使用
File -> Project Structure -> Artifacts打開到這個(gè)界面,然后點(diǎn)擊+號(hào),選擇jar下的from modules with dependencies

Module會(huì)自動(dòng)選擇當(dāng)前項(xiàng)目,Main Class需要選擇Main.java,并且JAR files from dependencies 需要選擇為copy to the output directory and link via mainfest
點(diǎn)擊OK然后Apply

就會(huì)多出一個(gè)項(xiàng)目名稱的jar包在這里
然后點(diǎn)擊Build -> Build Artifacts再在新界面選擇點(diǎn)擊Build

等待打包完成,這個(gè)時(shí)候會(huì)在我們的out文件夾下的artifacts文件夾會(huì)看到我們剛剛打包后的jar包
關(guān)閉我們的項(xiàng)目,然后啟動(dòng)該jar包
java -jar PureJavaDemo.jar

可以看到如上截圖成功執(zhí)行了jar,往user表加些數(shù)據(jù)再次請(qǐng)求postman驗(yàn)證是否可用

{
    "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"
        }
    ]
}

可以看到正常的訪問,但是有一點(diǎn)需要注意,打包之后的jar需要和依賴放在同一個(gè)文件夾下

項(xiàng)目GIT

純java后端項(xiàng)目DEMO

優(yōu)缺點(diǎn)

綜上,我們已經(jīng)很清晰明了的知道java是怎么去運(yùn)作我們的項(xiàng)目了,但是還是那句話,這個(gè)只是讓你更好的學(xué)習(xí)和了解java,真正要開發(fā)一個(gè)項(xiàng)目還是選擇Maven,Spring框架,如下我列舉了一些純java項(xiàng)目優(yōu)缺點(diǎn)

優(yōu)點(diǎn)
?? 輕量: 啟動(dòng)快,內(nèi)存占用第,無框架開銷
?? 自主掌控: 自主實(shí)現(xiàn)邏輯,可以深度理解底層機(jī)制(HTTP/TCP等)
??學(xué)習(xí)價(jià)值高: 對(duì)于掌握基礎(chǔ)友好

缺點(diǎn)
??開發(fā)效率低: 手動(dòng)實(shí)現(xiàn)路由,依賴注入等,重復(fù)造輪子,缺少標(biāo)準(zhǔn)項(xiàng)目結(jié)構(gòu)
??維護(hù)成本高: 自行管理依賴版本,缺少自動(dòng)化測試支持,擴(kuò)展性差
??團(tuán)隊(duì)協(xié)作難: 無統(tǒng)一的開發(fā)規(guī)范,項(xiàng)目結(jié)構(gòu)依賴個(gè)人風(fēng)格

結(jié)語

到此這篇關(guān)于IDEA實(shí)現(xiàn)純java項(xiàng)目并打包jar(不使用Maven,Spring)的文章就介紹到這了,更多相關(guān)DEA純java項(xiàng)目打包jar內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • Java的靜態(tài)類型檢查示例代碼詳解

    Java的靜態(tài)類型檢查示例代碼詳解

    本文將使用幾個(gè)代碼示例,深入講解Java中的類型檢查機(jī)制。一旦完全理解了本文的例子,就完全掌握了Java中的靜態(tài)類型檢查,感興趣的朋友一起看看吧
    2017-11-11
  • Java的Hibernate框架中用于操作數(shù)據(jù)庫的HQL語句講解

    Java的Hibernate框架中用于操作數(shù)據(jù)庫的HQL語句講解

    這篇文章主要介紹了Java的Hibernate框架中用于操作數(shù)據(jù)庫的HQL語句講解,Hibernate是Java的SSH三大web開發(fā)框架之一,需要的朋友可以參考下
    2016-01-01
  • SpringCloud?Bus組件的使用配置詳解

    SpringCloud?Bus組件的使用配置詳解

    bus稱之為springcloud中消息總線,主要用來在微服務(wù)系統(tǒng)中實(shí)現(xiàn)遠(yuǎn)端配置更新時(shí)通過廣播形式通知所有客戶端刷新配置信息,避免手動(dòng)重啟服務(wù)的工作,這篇文章主要介紹了SpringCloud?Bus組件的使用,需要的朋友可以參考下
    2022-03-03
  • macOS下Spring Boot開發(fā)環(huán)境搭建教程

    macOS下Spring Boot開發(fā)環(huán)境搭建教程

    這篇文章主要為大家詳細(xì)介紹了macOS下Spring Boot開發(fā)環(huán)境搭建教程,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2018-01-01
  • Java的LinkedHashSet源碼深入講解

    Java的LinkedHashSet源碼深入講解

    這篇文章主要介紹了Java的LinkedHashSet源碼深入講解,LinkedHashSet是HashSet的子類,而由于HashSet實(shí)現(xiàn)了Set接口,因此LinkedHashSet也間接實(shí)現(xiàn)了Set類,LinkedHashSet類屬于java.base模塊,java.util包下,需要的朋友可以參考下
    2023-09-09
  • mybatis-plus 攔截器敏感字段加解密的實(shí)現(xiàn)

    mybatis-plus 攔截器敏感字段加解密的實(shí)現(xiàn)

    數(shù)據(jù)庫在保存數(shù)據(jù)時(shí),對(duì)于某些敏感數(shù)據(jù)需要脫敏或者加密處理,本文主要介紹了mybatis-plus 攔截器敏感字段加解密的實(shí)現(xiàn),感興趣的可以了解一下
    2021-11-11
  • Java線程中斷的本質(zhì)深入理解

    Java線程中斷的本質(zhì)深入理解

    Java的中斷是一種協(xié)作機(jī)制。也就是說調(diào)用線程對(duì)象的interrupt方法并不一定就中斷了正在運(yùn)行的線程,它只是要求線程自己在合適的時(shí)機(jī)中斷自己,本文將詳細(xì)介紹,需要了解的朋友可以參考下
    2012-12-12
  • 淺談Mybatis之參數(shù)傳遞的幾種姿勢

    淺談Mybatis之參數(shù)傳遞的幾種姿勢

    在mybatis的日常開發(fā)中,mapper接口中定義的參數(shù)如何與xml中的參數(shù)進(jìn)行映射呢?本文就詳細(xì)的介紹一下,感興趣的可以了解一下
    2021-09-09
  • Spring Boot 實(shí)例代碼之通過接口安全退出

    Spring Boot 實(shí)例代碼之通過接口安全退出

    這篇文章主要介紹了Spring Boot 實(shí)例代碼之通過接口安全退出的相關(guān)資料,需要的朋友可以參考下
    2017-09-09
  • SpringBoot+Vue前后端分離實(shí)現(xiàn)請(qǐng)求api跨域問題

    SpringBoot+Vue前后端分離實(shí)現(xiàn)請(qǐng)求api跨域問題

    這篇文章主要介紹了SpringBoot+Vue前后端分離實(shí)現(xiàn)請(qǐng)求api跨域問題,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2020-06-06

最新評(píng)論