The project's README from github.com/zengyunhua/Mestudy. As one markdown file: README.md.
A reference implementation of a Chinese social-insurance / e-government backend.
For maintainers preparing an open-source programme application, see the application readiness and independent-reproduction guide.
Mestudy is a multi-module Maven workspace that collects the backend services behind a provincial social-insurance and online government-service platform. It is not a toy sample: the modules implement real business flows — social-insurance contribution queries, social-security card lifecycle, employment/job-seeking services, hospital registration, face verification, electronic signature, and draft-based online service applications.
The code is published as a reference architecture for engineers who have to build or maintain systems with the same shape: a servlet container, XML-wired Spring, MyBatis mappers against Oracle, Redis-backed sessions, SOAP bridges to legacy government interfaces, and a token-authenticated HTTP client SDK for downstream terminals.
If you are looking for a modern Spring Boot starter, this is deliberately not one. The value here is the domain modelling and the integration patterns that show up when a Java system has to talk to a dozen heterogeneous government backends.
| Pattern | Where to look |
|---|---|
| Token-authenticated client SDK with self-renewing heartbeat | IFaceHttpsClient |
| Uniform response envelope shared by ~350 endpoints | Result |
| Multi-datasource wiring with c3p0 + MyBatis | applicationContext.xml |
| SOAP (Axis) → REST adapter for a legacy HIS system | HangTianHisController |
| Draft / submit / audit state machine for online services | DraftsController |
| Startup-time resource bootstrapping | StartupListener |
| Module | Artifact | What it does | Size |
|---|---|---|---|
IFaceSuportService |
sisp_IFaceSuportService |
Core interface service. Social-insurance queries, card services, employment, hospital, face verification, SMS, WeChat, bank/fee channels. Also ships the reusable client SDK jar (classifier=client). |
286 Java files |
NetworkOfficeService |
sisp_NetworkOfficeService |
Online government-service portal. Application drafts, submission, audit trail, electronic signature (PDF stamping), area/administrative division data. | 129 Java files |
IFaceSuperService_hn |
sisp_IFaceSuperService_hn |
Province-specific (Henan) variant of the interface service: card + social-insurance controllers against the provincial gateway. | 60 Java files |
InterfaceFunction |
sisp_InterfaceFunction |
Platform security administration: users, roles, function/permission trees, login. | 49 Java files |
NetPortalManagement |
sisp_NetPortalManagement |
Lightweight portal administration: portal users, policy documents, external web-connection registry. Uses standard JDBC and Jersey with a configurable API-token filter. | 16 Java files |
All modules share the group id com.tecsun.sisp and are packaged as war for
deployment into a servlet container.
The diagram and request lifecycle below describe IFaceSuportService, not a
universal architecture for all five modules. Four modules use Spring MVC and MyBatis;
NetPortalManagement uses standard JDBC/Jersey. There is no shared
common artifact —
each module carries its own copy of common/util, which keeps modules independently
deployable at the cost of some duplication.
flowchart TB
subgraph Channel["Channel layer"]
T["Self-service terminal<br/>(TSB client SDK)"]
W["Web portal / JSP"]
X["WeChat / SMS"]
end
subgraph Web["Servlet container (Tomcat / WebLogic)"]
F["CharacterEncodingFilter<br/>HiddenHttpMethodFilter"]
D["DispatcherServlet<br/>springMVC-servlet.xml"]
L["StartupListener<br/>Redis + thread pool bootstrap"]
C["@Controller<br/>BaseController"]
S["Service / ServiceImpl"]
M["MyBatis Mapper<br/>DAO + mappings/*.xml"]
end
subgraph Infra["Infrastructure"]
R[("Redis<br/>token / session / dictionary")]
O[("Oracle<br/>sisp · sisp_public · business schemas")]
P["c3p0 pool<br/>multi-datasource"]
end
subgraph Ext["External systems"]
G["Provincial social-insurance gateway<br/>(SOAP / Axis)"]
H["Hospital HIS<br/>(SOAP)"]
B["Biometric / face service"]
K["Bank & fee channels"]
end
T --> F
W --> F
X --> F
F --> D --> C --> S --> M --> P --> O
C --> R
S --> G
S --> H
S --> B
S --> K
L -.-> R
web.xml loads config/applicationContext.xml into the root context and registers
StartupListener, which initialises the Redis pool (DataBase.init()) and the
shared thread pool (ThreadPoolUtil.init()) before the first request is served.DispatcherServlet is mapped to / and scans only @Controller beans from
com.tecsun.sisp.iface.server.controller.BaseController and return a Result (statusCode / message /
data) or a ResultVerify for paged payloads. statusCode is "200" on success and
"0" on failure — see API overview.src/main/resources/mappings/ and is bound in applicationContext.xml.HttpClient helpers, and are wrapped so a downstream outage degrades into a
Result with a failure code rather than a 500.| Concern | Choice | Notes |
|---|---|---|
| Language / runtime | Java 8 (source/target 1.8) | Level is set once in the root POM via maven.compiler.source/target; modules must not override it |
| Web framework | Spring MVC 4.0.8.RELEASE | XML configuration, no Spring Boot |
| Persistence | MyBatis 3.2.4 and JDBC | Mapper interfaces + XML in the Spring modules; parameterized JDBC repositories in portal administration |
| Connection pool | c3p0 (ComboPooledDataSource) where configured |
NetworkOfficeService uses DriverManagerDataSource; NetPortalManagement opens scoped JDBC connections |
| Database | Oracle 10g/11g | Multiple schemas per module |
| Cache / session | Redis via Jedis | Dictionary cache, interface token, channel state |
| SOAP | Apache Axis 1.x | Generated stubs for provincial gateway / HIS |
| HTTP client | Apache HttpClient 4.1 + Jersey 1.15 | Client SDK and inter-service calls |
| JSON | Gson + net.sf.json |
Both are in use; new code should prefer Gson |
| Logging | SLF4J + Log4j 1.2 | log4j.properties / log4j.xml per module |
| Packaging | war |
Servlet 2.5 descriptor |
--add-opens
workarounds for Axis and c3p0git clone https://github.com/zengyunhua/Mestudy.git
cd Mestudy
# Build and verify all five modules
mvn -B verify
# IFaceSuportService/target/IFaceSuportService-V1.0.0.150630.war -> deploy
# IFaceSuportService/target/IFaceSuportService-V1.0.0.150630-client.jar -> client SDK
# IFaceSuperService_hn/target/IFaceSuperService_hn-V1.0.0.190107.war
# InterfaceFunction/target/InterfaceFunction-V1.0.0.150630.war
# NetworkOfficeService/target/NetworkOfficeService-V1.0.0.180612.war
# NetPortalManagement/target/NetPortalManagement-V1.0.0.150630.war
The repository root holds an aggregator pom.xml, so Maven works from the top of the
tree. All five modules now resolve from public dependencies and are part of the default
reactor. Each module keeps its own coordinates and version — the root POM supplies the
module list, plugin versions, source encoding and Java 8 compiler level (1.8).
On JDK 8, run the public modules' unit tests without Oracle, Redis, or a deployed servlet container:
mvn -B test
The public reactor now includes NetPortalManagement; its JDBC repositories compile
without proprietary artifacts. The existing tests cover client, filter, paging, utility,
controller, Spring-context and build-hygiene behavior; they do not prove deployment or
cover every Oracle business flow. CI runs the same command with forked tests against an
isolated Maven repository, then applies scripts/verify_public_build.py to all WARs and
Surefire reports.
Legacy HTTP smoke tests are intentionally excluded from this command because they
require a running deployment and local fixtures. On Windows, if Surefire cannot start
a forked JVM because %TEMP% contains non-ASCII characters — the usual case when the
account name is Chinese — point the temp directory at an ASCII path:
mvn -B -Djava.io.tmpdir=D:\mvn-tmp package (create the directory first).
-DforkCount=0 also works but loses per-test isolation. See
troubleshooting.
This is a public dependency build, not a claim that a fresh clone has an Oracle
database or platform proxy available. NetPortalManagement now starts only after its
JDBC and API-token configuration is supplied.
| Module | Public build | In default reactor | Blocking dependency |
|---|---|---|---|
IFaceSuportService |
yes | yes | — |
IFaceSuperService_hn |
yes | yes | — |
InterfaceFunction |
yes | yes | — (the private coordinates it declared were unused and are gone) |
NetworkOfficeService |
yes | yes | — (one missing entity class was reconstructed) |
NetPortalManagement |
yes | yes | Oracle JDBC, external platform proxy for photo/log endpoints, and a configured API token |
Two modules needed work to get here, and they needed different things.
InterfaceFunction declared com.tecsun.sisp_public:aamanagement-client and
bee:xx.tool. No source file imports either, no Class.forName mentions them, and the
former web.xml references to the AAM client were only commented-out filters
(now removed) —
so they were dead declarations copied from a sibling POM. NetworkOfficeService was the
same.
NetworkOfficeService needed a second fix on top of that: removing the declarations
exposed a missing source file. Four classes and
mappings/draftsDAO.xml refer to
com.tecsun.sisp.net.modules.entity.response.BanjianVo, which was never published. It
has been reconstructed in
BanjianVo.java
from the columns the mapper proves exist, with the provenance recorded in its Javadoc.
That is the one place in this repository where the code is not the original: if you have
the real schema, diff it against your DDL.
Compiling was not the same as packaging correctly. The same module also shipped
javax.servlet:servlet-api and spring-test inside WEB-INF/lib, pointed one datasource
at another schema's ${jdbc.*} key, loaded two of its three mapper XML files, and mapped
/views/** at WEB-INF/ itself — which served classes/config.properties on request.
All of that now fails a test instead of a deployment: SpringContextLoadTest loads the
real context and asserts every datasource URL and every mapper statement. The full list is
in the CHANGELOG.
NetPortalManagement previously depended on Bee ORM, Bee startup classes, xx.tool and
the AAM Jersey filter. Those dependencies have been replaced with plain DTOs, a
parameterized JDBC repository, standard Jersey servlet bootstrapping, AppConfig and a
fail-closed API-token filter. The migration preserves the existing resource paths while
making the security and configuration boundary explicit in the module guide.
Everything else — Spring, MyBatis, Axis, Jersey, kaptcha and the Oracle JDBC driver — resolves from Maven Central.
Private mirrors. The POMs no longer hard-code an internal Nexus. If your organisation proxies Maven Central, declare the mirror in
~/.m2/settings.xmlinstead of in the project POM. See docs/GETTING_STARTED.md.
# 1. Copy the configuration template and fill in your own values
cp IFaceSuportService/src/main/resources/config.properties.example IFaceSuportService/src/main/resources/config.properties
# 2. Deploy the war (context path is /sisp by convention)
cp IFaceSuportService/target/IFaceSuportService-*.war "$CATALINA_HOME/webapps/sisp.war"
# 3. Start the container
$CATALINA_HOME/bin/startup.sh
Port 8080 is only an example: use the Tomcat HTTP connector port and configure Oracle, Redis and all required data sources before deploying. A successful WAR build does not verify runtime behaviour. See the deployment guide.
IFaceSuportService publishes a slim client jar containing only **/client/** and
**/common/** classes. Consumers initialise it once, then call typed methods.
// Initialise once per JVM. Spawns a heartbeat thread that renews the token.
IFaceHttpsClient.ClientInit(
"10.0.0.10", // host
8080, // port
60, // token refresh interval, minutes (floor is 60)
false, // useHttps
"TSB", // channel code
"sisp" // platform context path
);
// Then call the typed API
SecQueryBean bean = new SecQueryBean();
bean.setId("110101199001010015");
bean.setName("...");
bean.setChannelcode("SelfService");
Page<TsgrjfxxVO> page = IFaceHttpsClient.getPersonPesionPay(bean);
System.out.println(page.getData().size());
The heartbeat calls POST {context}/iface/user/checkLogin and stores the returned
tokenId; subsequent SDK requests send X-Token-Id as a header. Because the token is held
in a static field and the heartbeat thread is a singleton, the SDK is bound to a
single target server per JVM. See docs/CLIENT_SDK.md for the
full reference.
Every module ships a config.properties.example; copy it to config.properties and
keep the real file untracked. The four Spring MVC modules read it through
<context:property-placeholder ignore-unresolvable="true">, so ${key} resolves in
their XML — and an unknown key is left in place as the literal ${key} rather than
failing at startup. NetPortalManagement resolves keys through AppConfig, which
checks a JVM system property, then config.properties, then an environment variable
(jdbc.url → NPM_JDBC_URL), and throws on a missing required key instead of returning
null. Its datasource is therefore jdbc.* in this same file, not a separate ds.xml,
and api.token is mandatory — the module refuses to start without it. See its
module guide.
| Key group | Purpose |
|---|---|
jdbc.<name>.* |
Driver, URL, credentials and pool sizing per datasource |
redis_core_database |
Redis endpoint as host_port |
redis_iface_expx |
Token / cache TTL in minutes (multiplied by 60 internally) |
platform_context_path |
Deployed context path, default /sisp |
inner_proxy_ip / inner_proxy_port |
Internal proxy used for inter-service calls |
biometrics.* |
Face-verification gateway endpoint and credentials |
signpdf.* |
Electronic-signature service endpoint, font and template paths |
Full reference: docs/CONFIGURATION.md.
The Spring MVC modules commonly use a Result envelope for JSON responses, and
NetPortalManagement's JsonResponse emits the same three fields:
{
"statusCode": "200",
"message": "success",
"data": { }
}
Paged endpoints add pageNo, pageSize and count:
{
"statusCode": "200",
"message": "success",
"data": [ ],
"pageNo": 1,
"pageSize": 20,
"count": 137
}
Across the workspace there are 358 @RequestMapping declarations, grouped by
domain prefix (/iface/rest/, /iface/cardInfo/, /iface/user/, ...). The
endpoint index lists them by controller.
This repository is a curated archive of production-derived modules, published for reference. It is maintained on a best-effort basis.
docs/.NetPortalManagement still needs Oracle and a
configured platform proxy for meaningful runtime checks.scripts/verify_public_build.py
requires a nonempty WAR and at least one passing test per module, and CI runs it after
mvn -B verify: 46 tests in total (12/8/7/4/15). The portal module's tests stop at the
boundary — AppConfig resolution order, ApiTokenFilter rejection and the upload
resource's HTTP method; none of which needs a database. The JDBC repository remains
uncovered and needs an Oracle-compatible fixture.These are documented on purpose — they are the honest state of the code, and each one is a good first contribution.
.example templates instead of tracked local config.properties / ds.xml, but
Git history still contains credential-, payment-signing-key- and identity-shaped
values. Their provenance and real-world use are unverified. The
security review records a category-only inventory and
the evidence/approval process. If a value was provisioned, its owner must revoke
or rotate it with the provider (especially payment signing material) before any
coordinated history cleanup. Do not assume every match identifies a real person
or a live secret; do not paste historical values into public channels.common layer. Each module re-implements Result, Page,
CommUtil, AESUtil. 53 class names exist in more than one module, and 51 of those
53 have drifted apart — only DevBean and SecretKeyBean are still byte-identical
(between IFaceSuportService and IFaceSuperService_hn). The spread is wide:
Constants exists in four copies of 895, 69, 31 and 30 lines; BaseController in
five. Consolidating them into a shared artifact is the single most valuable refactor
available here, but it is not a mechanical merge — the smallest copy is usually the
only one a given module actually calls, so every divergence has to be resolved by
reading its callers.Page have focused assertion-based tests,
but most business flows are not covered. Legacy HTTP smoke tests require a
running service and local fixtures, so they are excluded from default tests.v1.0.0 and v1.1.0 are tagged
and described in CHANGELOG.md, but the per-module artifact versions in
the POMs still carry their original internal numbers (V1.0.0.150630,
V1.0.0.190107). The public-build and portal-port work since v1.1.0 is in
Unreleased.See docs/ROADMAP.md. Near-term:
target/ and the real config.properties filesv1.0.0InterfaceFunction into the default reactor (its private coordinates were unused)BanjianVo so NetworkOfficeService builds publiclycommon layer and one controller per module| Document | Contents |
|---|---|
| docs/GETTING_STARTED.md | Zero-to-running in ~15 minutes |
| docs/ARCHITECTURE.md | Layering, contexts, request lifecycle, cross-cutting concerns |
| docs/CONFIGURATION.md | Every configuration key, with defaults |
| docs/API_OVERVIEW.md | Response envelope, error codes, endpoint index |
| docs/CLIENT_SDK.md | Using IFaceHttpsClient from a Java consumer |
| docs/TROUBLESHOOTING.md | Build failures, encoding issues, Oracle/Redis gotchas |
| docs/ROADMAP.md | Where this is going |
| docs/SECURITY_REVIEW.md | Category-only inventory of historical sensitive-looking values and the remediation process |
| docs/MODULE_REVIEW_IFACESUPORTSERVICE.md | Code review of the core interface module |
| docs/OPEN_SOURCE_APPLICATION_GUIDE.md | What a reviewer can verify today, and how to reproduce it independently |
| docs/RELEASE_CHECKLIST.md | Reproducible release, tagging and publication checklist |
| Per-module READMEs | Linked from the module map |
Issues and pull requests are welcome — especially the items in Known limitations. Please read CONTRIBUTING.md first, and note that all participation is governed by the Code of Conduct. Repository ownership and review routing are recorded in .github/CODEOWNERS; dependency updates are proposed monthly by Dependabot.
Good first issues: adding a test, replacing a hard-coded constant with a configuration key, translating a class-level comment into English Javadoc, or writing the missing SQL for one of the unbound mapper methods listed in the CHANGELOG.
Do not open a public issue for a vulnerability. See SECURITY.md.
Third-party attribution is recorded in NOTICE. A small number of files
(Dialect, PreparePaginationInterceptor, Reflections) are copied from
JeeSite and keep their original @author
tags — please leave those intact if you fork this project.
This codebase is derived from systems built for Chinese public-service institutions. It is published for educational and reference purposes. It is not affiliated with, endorsed by, or supported by any government agency. Credential- and identity-shaped historical values have not all been verified as synthetic or never provisioned; do not use them against live systems. You are responsible for complying with local law — including personal-information protection rules — before deploying anything derived from this repository.