Skip to content

huiz6/server-commons

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

3 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

server-commons

server-commons is a Java utility library for Spring Boot server applications. It packages reusable helpers for Redis, distributed locking and ID generation, synchronous and asynchronous HTTP calls, Elasticsearch, date/time operations, bit manipulation, AES encryption, and client IP extraction.

The library is published as a regular JAR and is intended to be consumed by other services; it does not contain a production application entry point.

Project coordinates

Item Value
Group ID outfox.infra
Artifact ID server-commons
Current version 1.2.4
Java Java 8 or later
Build tool Gradle 6.6 (wrapper included)
Spring Boot baseline 2.3.5.RELEASE

Features

Area Main classes Capabilities
Redis RedisConfig, RedisUtil<T> JSON serialization, string values, counters, hashes, sets, expiration, deletion, and basic locks
Locking LockUtil, RedisLockUtil Redis-backed lock facade
Distributed IDs DistributedIdGenerateUtils Synchronized 53-bit IDs containing a timestamp, worker ID, and per-millisecond sequence
HTTP HttpClientUtil, AsyncHttpClientUtil Pooled Apache HTTP clients for GET, POST, JSON, form, upload, and DELETE requests
Elasticsearch ElasticsearchUtil<T> Insert, get/delete by ID, delete index, and resolve an index name from @Document
Date and time DateTimeUtils Day/week/month boundaries, offsets, timestamp formatting, and parsing
Math and bits MathUtils Masks, random booleans, bit inspection/update, and bit-filtered integer ranges
Encryption AESUtil Legacy AES string encryption/decryption with hexadecimal output
Networking IPUtils Client IP extraction from common reverse-proxy headers

Installation

Gradle

Add the Maven repository that hosts the artifact, then add:

dependencies {
    implementation group: 'outfox.infra', name: 'server-commons', version: '1.2.4'
}

Maven

<dependency>
    <groupId>outfox.infra</groupId>
    <artifactId>server-commons</artifactId>
    <version>1.2.4</version>
</dependency>

For local development, install the artifact into your local Maven repository first:

bash ./gradlew install

Spring configuration

This project does not register Spring Boot auto-configuration metadata. If you use its Spring-managed Redis, lock, ID, or Elasticsearch classes, include the package in component scanning or import only the configuration/components you need.

@SpringBootApplication
@ComponentScan(basePackages = {
        "com.example.application",
        "outfox.infra.server.commons"
})
public class Application {
    public static void main(String[] args) {
        SpringApplication.run(Application.class, args);
    }
}

RedisUtil requires a non-blank key prefix. Standard Spring Boot Redis connection properties are also required:

spring:
  redis:
    host: localhost
    port: 6379
    timeout: 2s

infra:
  redis:
    key:
      prefix: MY-SERVICE

Every key passed to RedisUtil is stored as <prefix>::<key>. RedisConfig configures a RedisTemplate<String, T> with string keys and Jackson JSON values.

Configure Elasticsearch using the Spring Boot 2.3 REST client properties when ElasticsearchUtil is needed:

spring:
  elasticsearch:
    rest:
      uris: http://localhost:9200

Usage

Redis

@Service
public class CacheService {
    private final RedisUtil<String> redis;

    public CacheService(RedisUtil<String> redis) {
        this.redis = redis;
    }

    public void storeSession(String sessionId, String value) {
        redis.setNonNull("session:" + sessionId, value, 1800);
    }

    public String getSession(String sessionId) {
        return redis.get("session:" + sessionId);
    }
}

Other Redis operations include exists, incr, setIfAbsent, hset/hget/hdel, sadd/smember/smembers, expire, pexpire, and single or bulk del.

Redis lock

@Autowired
private LockUtil lockUtil;

public void runOnce() {
    if (!lockUtil.acquireLock("daily-job", 30)) {
        return;
    }
    try {
        // Protected work
    } finally {
        lockUtil.releaseLock("daily-job");
    }
}

The lock timeout is in seconds.

Distributed ID

After Spring has initialized DistributedIdGenerateUtils and assigned a worker ID through Redis:

long id = DistributedIdGenerateUtils.generateId();

The ID layout is 41 timestamp bits, 5 worker bits, and 7 sequence bits. A single process can generate up to 128 IDs per millisecond before waiting for the next millisecond.

Synchronous HTTP

Timeout values are milliseconds. The url argument is a host name because the implementation passes it to URIBuilder.setHost; use query parameters for the supported request target.

HttpClientUtil client = new HttpClientUtil(
        1000, // wait for a pooled connection
        2000, // connect timeout
        5000, // socket timeout
        100   // maximum pooled connections
);

Map<String, String> query = new HashMap<>();
query.put("id", "42");

JSONObject response = client.get("https", "api.example.com", query);
int status = response.getIntValue("code");
String body = response.getString("body");

All synchronous methods return a Fastjson JSONObject containing the HTTP status as code and the unparsed response entity as body. postJSON adds Content-Type: application/json; the class also supports URL-encoded forms, raw string bodies, multipart file upload, and DELETE.

Asynchronous HTTP

AsyncHttpClientUtil client = new AsyncHttpClientUtil(1000, 2000, 5000, 100);

Future<HttpResponse> future = client.get(
        "https",
        "api.example.com",
        Collections.singletonMap("id", "42"),
        Collections.emptyMap(),
        new AsyncHandlerAdapter() {
            @Override
            public Object completed(HttpResponse response) {
                JSONObject result = BaseHttpClientUtil.getJSONResponse(response);
                // Process result
                return result;
            }
        }
);

Implement IHandler or extend AsyncHandlerAdapter to handle completion, failure, and cancellation. The returned Future<HttpResponse> can be used to wait for or cancel the request.

Elasticsearch

@Document(indexName = "customers")
public class Customer {
    @Id
    private String id;
    // fields, getters, and setters
}

@Autowired
private ElasticsearchUtil<Customer> elasticsearch;

String id = elasticsearch.insert("customers", customer);
Customer stored = elasticsearch.queryById(Customer.class, id);
elasticsearch.deleteById(Customer.class, id);

Operations log Elasticsearch exceptions and return null or false on failure. getIndexName(Customer.class) reads the index name from @Document and throws if the annotation is missing.

Standalone utilities

String cipherText = AESUtil.encryptStr("payload");
String plainText = AESUtil.decryptStr(cipherText);

long startOfDay = DateTimeUtils.getDayStartTime(System.currentTimeMillis());
String formatted = DateTimeUtils.convertToDateTimeStr(System.currentTimeMillis());

boolean thirdBitSet = MathUtils.checkBit(4, 2);
int withFirstBitSet = MathUtils.setAssignBitIsOne(2, 0);

String clientIp = IPUtils.getIpAddr(request);

IPUtils checks X-Original-Forwarded-For, X-Forwarded-For, and several legacy proxy headers before falling back to HttpServletRequest.getRemoteAddr(). Only trust forwarded headers when they are sanitized by a trusted proxy.

Build and test

The wrapper file is included but is not executable in the current repository checkout, so invoke it through the shell on Unix-like systems:

bash ./gradlew jar

The JAR is written to build/libs/server-commons-<version>.jar.

The test sources cover AES, date/time, and math helpers. Redis and Elasticsearch integration test classes are marked @Ignore; enable them only after replacing the test environment endpoints in src/test/resources/application-test.yml with accessible, non-production services.

The current Gradle configuration does not register Lombok as a test annotation processor, although ElasticsearchTestData uses Lombok-generated builders and accessors. Consequently, bash ./gradlew test fails during compileTestJava. Add the following dependency before running the complete test suite:

dependencies {
    testAnnotationProcessor group: 'org.projectlombok', name: 'lombok', version: '1.18.16'
}

Then run:

bash ./gradlew clean test

Publishing

For local development, use a snapshot version and install locally:

bash ./gradlew jar
bash ./gradlew install

To publish to a Maven repository, fill in the repository URL and credentials in build.gradle, choose the intended release or snapshot version, and run:

bash ./gradlew publish

Use snapshot artifacts only for local/development work and fixed versions for test and production environments.

Important limitations

  • AESUtil contains a fixed key and uses the provider default AES transformation (normally ECB with PKCS#5 padding). It provides compatibility, not modern secure encryption. Do not use it for new sensitive data; prefer an authenticated mode such as AES-GCM with externally managed keys.
  • Redis lock values do not contain an owner token, and release is a plain delete. A client can therefore delete a lock acquired by another client after expiration/reacquisition. Use a token-checked Lua release or a mature locking library when correctness is critical.
  • Distributed worker IDs are allocated from one Redis counter and wrap after 32 values. They are not leased or tied to process lifetime, so deployments must evaluate collision risk during restarts and at larger scale.
  • Day-boundary and schedule methods use a fixed UTC+8 offset, while some other date methods use the JVM default time zone. Confirm that behavior before using the helpers outside UTC+8 deployments.
  • The HTTP utility API builds a URI from a scheme and host only; it has no separate path parameter. It also does not expose an explicit lifecycle/close method for its pooled clients.
  • RedisConfig enables Jackson default typing for non-final values. Review serialized types and trust boundaries before reading Redis data written by untrusted parties.

Project layout

src/main/java/outfox/infra/server/commons/
├── elasticsearch/   Elasticsearch helper
├── http/            Shared, synchronous, and asynchronous HTTP clients
├── lock/            Lock interface and Redis implementation
├── redis/           Redis template configuration and operations
├── AESUtil.java
├── DateTimeUtils.java
├── DistributedIdGenerateUtils.java
├── IPUtils.java
└── MathUtils.java

About

No description, website, or topics provided.

Resources

Stars

0 stars

Watchers

1 watching

Forks

Releases

No releases published

Packages

 
 
 

Contributors

Languages