diff --git a/.gitignore b/.gitignore index a8b0d1d..aa724b7 100644 --- a/.gitignore +++ b/.gitignore @@ -1,35 +1,15 @@ -# ---> Android -# Gradle files -.gradle/ -build/ - -# Local configuration file (sdk path, etc) -local.properties - -# Log/OS Files -*.log - -# Android Studio generated files and folders -captures/ -.externalNativeBuild/ -.cxx/ -*.apk -output.json - -# IntelliJ *.iml -.idea/ -misc.xml -deploymentTargetDropDown.xml -render.experimental.xml - -# Keystore files -*.jks -*.keystore - -# Google Services (e.g. APIs or Firebase) -google-services.json - -# Android Profiling -*.hprof - +.gradle +/local.properties +/.idea/caches +/.idea/libraries +/.idea/modules.xml +/.idea/workspace.xml +/.idea/navEditor.xml +/.idea/assetWizardSettings.xml +.DS_Store +/build +/captures +.externalNativeBuild +.cxx +local.properties diff --git a/app/.gitignore b/app/.gitignore new file mode 100644 index 0000000..42afabf --- /dev/null +++ b/app/.gitignore @@ -0,0 +1 @@ +/build \ No newline at end of file diff --git a/app/build.gradle b/app/build.gradle new file mode 100644 index 0000000..88e2a3f --- /dev/null +++ b/app/build.gradle @@ -0,0 +1,43 @@ +plugins { + id 'com.android.application' +} + +android { + namespace 'cn.org.landcloud.survey' + compileSdk 32 + + defaultConfig { + applicationId "cn.org.landcloud.survey" + minSdk 21 + targetSdk 32 + versionCode 1 + versionName "1.0" + + testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" + } + + buildTypes { + release { + minifyEnabled false + proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro' + } + } + compileOptions { + sourceCompatibility JavaVersion.VERSION_1_8 + targetCompatibility JavaVersion.VERSION_1_8 + } +} + +dependencies { + + implementation 'androidx.appcompat:appcompat:1.5.1' + implementation 'com.google.android.material:material:1.6.1' + implementation 'androidx.constraintlayout:constraintlayout:2.1.4' + implementation project(path: ':ssl') + testImplementation 'junit:junit:4.13.2' + androidTestImplementation 'androidx.test.ext:junit:1.1.3' + androidTestImplementation 'androidx.test.espresso:espresso-core:3.4.0' + implementation "androidx.room:room-runtime:2.2.6" + annotationProcessor "androidx.room:room-compiler:2.2.6" + +} \ No newline at end of file diff --git a/app/proguard-rules.pro b/app/proguard-rules.pro new file mode 100644 index 0000000..481bb43 --- /dev/null +++ b/app/proguard-rules.pro @@ -0,0 +1,21 @@ +# Add project specific ProGuard rules here. +# You can control the set of applied configuration files using the +# proguardFiles setting in build.gradle. +# +# For more details, see +# http://developer.android.com/guide/developing/tools/proguard.html + +# If your project uses WebView with JS, uncomment the following +# and specify the fully qualified class name to the JavaScript interface +# class: +#-keepclassmembers class fqcn.of.javascript.interface.for.webview { +# public *; +#} + +# Uncomment this to preserve the line number information for +# debugging stack traces. +#-keepattributes SourceFile,LineNumberTable + +# If you keep the line number information, uncomment this to +# hide the original source file name. +#-renamesourcefileattribute SourceFile \ No newline at end of file diff --git a/app/src/androidTest/java/cn/org/landcloud/survey/ExampleInstrumentedTest.java b/app/src/androidTest/java/cn/org/landcloud/survey/ExampleInstrumentedTest.java new file mode 100644 index 0000000..4489e17 --- /dev/null +++ b/app/src/androidTest/java/cn/org/landcloud/survey/ExampleInstrumentedTest.java @@ -0,0 +1,26 @@ +package cn.org.landcloud.survey; + +import android.content.Context; + +import androidx.test.platform.app.InstrumentationRegistry; +import androidx.test.ext.junit.runners.AndroidJUnit4; + +import org.junit.Test; +import org.junit.runner.RunWith; + +import static org.junit.Assert.*; + +/** + * Instrumented test, which will execute on an Android device. + * + * @see Testing documentation + */ +@RunWith(AndroidJUnit4.class) +public class ExampleInstrumentedTest { + @Test + public void useAppContext() { + // Context of the app under test. + Context appContext = InstrumentationRegistry.getInstrumentation().getTargetContext(); + assertEquals("cn.org.landcloud.survey", appContext.getPackageName()); + } +} \ No newline at end of file diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml new file mode 100644 index 0000000..442f16d --- /dev/null +++ b/app/src/main/AndroidManifest.xml @@ -0,0 +1,35 @@ + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/assets/landcloud_demo.db b/app/src/main/assets/landcloud_demo.db new file mode 100644 index 0000000..bedb860 Binary files /dev/null and b/app/src/main/assets/landcloud_demo.db differ diff --git a/app/src/main/assets/phone_1.jpg b/app/src/main/assets/phone_1.jpg new file mode 100644 index 0000000..42222cc Binary files /dev/null and b/app/src/main/assets/phone_1.jpg differ diff --git a/app/src/main/assets/phone_panoramic_1.jpg b/app/src/main/assets/phone_panoramic_1.jpg new file mode 100644 index 0000000..e163623 Binary files /dev/null and b/app/src/main/assets/phone_panoramic_1.jpg differ diff --git a/app/src/main/assets/phone_video_1.mp4 b/app/src/main/assets/phone_video_1.mp4 new file mode 100644 index 0000000..d3f3e6f Binary files /dev/null and b/app/src/main/assets/phone_video_1.mp4 differ diff --git a/app/src/main/assets/photo_uav_1658133414992.jpg b/app/src/main/assets/photo_uav_1658133414992.jpg new file mode 100644 index 0000000..5304101 Binary files /dev/null and b/app/src/main/assets/photo_uav_1658133414992.jpg differ diff --git a/app/src/main/assets/photo_uav_1658133423647_panoramic.jpg b/app/src/main/assets/photo_uav_1658133423647_panoramic.jpg new file mode 100644 index 0000000..43549f3 Binary files /dev/null and b/app/src/main/assets/photo_uav_1658133423647_panoramic.jpg differ diff --git a/app/src/main/java/cn/org/landcloud/survey/MainActivity.java b/app/src/main/java/cn/org/landcloud/survey/MainActivity.java new file mode 100644 index 0000000..69de37e --- /dev/null +++ b/app/src/main/java/cn/org/landcloud/survey/MainActivity.java @@ -0,0 +1,156 @@ +package cn.org.landcloud.survey; + +import static cn.org.landcloud.survey.data.DataRepositories.RELATIVE_FJ_DIR; +import static cn.org.landcloud.survey.data.DataRepositories.RELATIVE_PATH; + +import android.Manifest; +import android.app.AlertDialog; +import android.content.DialogInterface; +import android.content.pm.PackageManager; +import android.os.Bundle; +import android.os.Environment; +import android.view.View; +import android.widget.TextView; + +import androidx.appcompat.app.AppCompatActivity; +import androidx.core.app.ActivityCompat; +import androidx.core.content.ContextCompat; + +import java.io.File; +import java.io.IOException; +import java.nio.charset.StandardCharsets; + +import cn.org.landcloud.security.Util; +import cn.org.landcloud.security.sm2.SM2EncDecUtils; +import cn.org.landcloud.security.sm2.SM2KeyVO; +import cn.org.landcloud.security.sm2.SM2SignVO; +import cn.org.landcloud.security.sm2.SM2SignVerUtils; +import cn.org.landcloud.security.sm3.SM3Utils; +import cn.org.landcloud.survey.data.DataRepositories; +import cn.org.landcloud.survey.data.LandSurveyDatabase; +import cn.org.landcloud.survey.util.Constants; +import cn.org.landcloud.survey.util.FileIOUtils; +import cn.org.landcloud.survey.util.Utils; + +public class MainActivity extends AppCompatActivity { + + private static final int REQUEST_CODE = 0x1000; + + private TextView logView; + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setContentView(R.layout.activity_main); + initView(); + checkPermissions(); + } + + + private void checkPermissions() { + if (ContextCompat.checkSelfPermission(this, Manifest.permission.WRITE_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED) { + if (ActivityCompat.shouldShowRequestPermissionRationale(this, Manifest.permission.WRITE_EXTERNAL_STORAGE)) { +// 申请权限 + ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE}, REQUEST_CODE); + } else { + ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE}, REQUEST_CODE); + } + + } + } + + private void initView() { + logView = findViewById(R.id.log_tv); + } + + @Override + public void onRequestPermissionsResult(int requestCode, String permissions[], int[] grantResults) { + super.onRequestPermissionsResult(requestCode, permissions, grantResults); + switch (requestCode) { + case REQUEST_CODE: { + if (grantResults.length > 0) { + for (int grantresult : grantResults) { + if (grantresult != PackageManager.PERMISSION_GRANTED) { + new AlertDialog.Builder(MainActivity.this).setTitle("系统提示") + .setMessage("有部分权限授权失败,请通过后台应用设置重新授权!") + .setPositiveButton("确定", new DialogInterface.OnClickListener() { + @Override + public void onClick(DialogInterface dialog, int which) {//确定按钮的响应事件 + finish(); + } + }).show(); + return; + } + } + + } + } + } + } + + @Override + protected void onDestroy() { + super.onDestroy(); + logView.setText(""); + } + + /** + * @param view + */ + public void createSSL(View view) { + SM2KeyVO result = SM2EncDecUtils.generateKeyPair(); + logView.append("--产生SM2密钥--:\n"); + logView.append("公钥:" + result.getPubHexInSoft() + "\n"); + logView.append("私钥:" + result.getPriHexInSoft() + "\n"); + } + + /** + * @param view + */ + public void initData(View view) { + logView.append("--开始生成样例成果db包--:\n"); + DataRepositories.getInstance().initData(this); + File file = new File(Environment.getExternalStorageDirectory(), RELATIVE_PATH); + LandSurveyDatabase.getInstance().destroy(); + logView.append("--样例成果db包生成完成,路径为--:" + file.getPath() + "\n"); + } + + /** + * @param view + */ + public void getJYM(View view) { + logView.append("--开始生成附件信息签名--:\n"); + + File file = new File(Environment.getExternalStorageDirectory(),RELATIVE_FJ_DIR+"phone_1.jpg"); + StringBuffer stringBuffer = new StringBuffer(); + try { + String fjhxz = SM3Utils.sm3(file); + stringBuffer.append(fjhxz).append(","); + } catch (IOException e) { + e.printStackTrace(); + } + // FJHXZ,PSSJ,Longitude,Latitude,PSFYJ,PSJD,PSHGJ,PSRY,ZSDM + stringBuffer.append("2022-10-18 15:42:56,119.98547,30.277615,41.0,239.0,2.0,test,1001"); + String jym = Utils.makeJYM(stringBuffer.toString(),Constants.TEST_PRIVATEKEY); + logView.append("--附件信息签名--:" + jym + "\n"); + } + + /** + * @param view + */ + public void getHash(View view) { + logView.append("--开始生成图片Hash--:\n"); + File file = new File(Environment.getExternalStorageDirectory(), RELATIVE_FJ_DIR+"phone_1.jpg"); + if (!file.isFile() || !file.exists()) { + logView.append("没有找到文件:" + file.getPath() + "\n"); + return; + } + try { + String hashCode = SM3Utils.sm3(file); + logView.append("--Hash值--:" + hashCode + "\n"); + } catch (IOException e) { + e.printStackTrace(); + logView.append("--生成Hash值失败--:" + e.getMessage() + "\n"); + } + } +} \ No newline at end of file diff --git a/app/src/main/java/cn/org/landcloud/survey/data/DBInfoDao.java b/app/src/main/java/cn/org/landcloud/survey/data/DBInfoDao.java new file mode 100644 index 0000000..f906da9 --- /dev/null +++ b/app/src/main/java/cn/org/landcloud/survey/data/DBInfoDao.java @@ -0,0 +1,54 @@ +package cn.org.landcloud.survey.data; + + +import androidx.room.Dao; +import androidx.room.Delete; +import androidx.room.Insert; +import androidx.room.OnConflictStrategy; +import androidx.room.Update; + +import java.util.List; + +import cn.org.landcloud.survey.data.bean.DBInfo; +import cn.org.landcloud.survey.data.bean.FJ; + + +@Dao +public interface DBInfoDao { + + + /** + * 插入一条新的附件 + * 如插入时发生冲突,处理方式为插入一个新的对象。 + * + * @param dbInfo + * @return + */ + @Insert(onConflict = OnConflictStrategy.REPLACE) + long insertDBInfo(DBInfo dbInfo); + + @Update + int updateDBInfo(DBInfo dbInfo); + + @Delete + int deleteDBInfo(DBInfo dbInfo); + + @Insert(onConflict = OnConflictStrategy.REPLACE) + void insertDBInfo(DBInfo... dbInfo); + + @Insert(onConflict = OnConflictStrategy.REPLACE) + void insertDBInfo(List dbInfos); + + @Update + void updateDBInfo(DBInfo... dbInfo); + + @Update + void updateDBInfo(List dbInfo); + + @Delete + void deleteDBInfo(DBInfo... dbInfo); + + @Delete + void deleteDBInfo(List dbInfo); + +} diff --git a/app/src/main/java/cn/org/landcloud/survey/data/DCHSXXDao.java b/app/src/main/java/cn/org/landcloud/survey/data/DCHSXXDao.java new file mode 100644 index 0000000..5498b90 --- /dev/null +++ b/app/src/main/java/cn/org/landcloud/survey/data/DCHSXXDao.java @@ -0,0 +1,53 @@ +package cn.org.landcloud.survey.data; + + +import androidx.room.Dao; +import androidx.room.Delete; +import androidx.room.Insert; +import androidx.room.OnConflictStrategy; +import androidx.room.Update; + +import java.util.List; + +import cn.org.landcloud.survey.data.bean.DCHSXX; + + +@Dao +public interface DCHSXXDao { + + + /** + * 插入一条新的附件 + * 如插入时发生冲突,处理方式为插入一个新的对象。 + * + * @param dchsxx + * @return + */ + @Insert(onConflict = OnConflictStrategy.REPLACE) + long insertDCHSXX(DCHSXX dchsxx); + + @Update + int updateDCHSXX(DCHSXX dchsxx); + + @Delete + int deleteDCHSXX(DCHSXX dchsxx); + + @Insert(onConflict = OnConflictStrategy.REPLACE) + void insertDCHSXX(DCHSXX... dchsxx); + + @Insert(onConflict = OnConflictStrategy.REPLACE) + void insertDCHSXX(List dchsxxs); + + @Update + void updateDCHSXX(DCHSXX... dchsxx); + + @Update + void updateDCHSXX(List dchsxx); + + @Delete + void deleteDCHSXX(DCHSXX... dchsxx); + + @Delete + void deleteDCHSXX(List fj); + +} diff --git a/app/src/main/java/cn/org/landcloud/survey/data/DataRepositories.java b/app/src/main/java/cn/org/landcloud/survey/data/DataRepositories.java new file mode 100644 index 0000000..c77ce23 --- /dev/null +++ b/app/src/main/java/cn/org/landcloud/survey/data/DataRepositories.java @@ -0,0 +1,476 @@ +package cn.org.landcloud.survey.data; + +import static cn.org.landcloud.survey.util.Constants.CERT_ORG_CODE; +import static cn.org.landcloud.survey.util.Constants.TEST_CER; +import static cn.org.landcloud.survey.util.Constants.TEST_CERT_ORG_PUBLICKEY; +import static cn.org.landcloud.survey.util.Constants.TEST_PUBLICKEY; + +import android.content.Context; +import android.os.Environment; + +import androidx.annotation.NonNull; + +import org.json.JSONObject; + +import java.io.File; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.nio.charset.StandardCharsets; +import java.util.HashMap; + +import cn.org.landcloud.security.Util; +import cn.org.landcloud.security.sm2.SM2SignVO; +import cn.org.landcloud.security.sm2.SM2SignVerUtils; +import cn.org.landcloud.security.sm3.SM3Utils; +import cn.org.landcloud.survey.util.Constants; +import cn.org.landcloud.survey.util.FileIOUtils; +import cn.org.landcloud.survey.util.TimeUtils; +import cn.org.landcloud.survey.util.Utils; +import cn.org.landcloud.survey.data.bean.DBInfo; +import cn.org.landcloud.survey.data.bean.DCHSXX; +import cn.org.landcloud.survey.data.bean.FJ; +import cn.org.landcloud.survey.data.bean.JMXX; +import cn.org.landcloud.survey.data.bean.KZXXYSJ; +import cn.org.landcloud.survey.data.bean.TBJBXX; + +public class DataRepositories { + + private static DataRepositories instance; + + public static final String DB_NAME = "landcloud_demo.db"; + public static final String FJ_NAME_1 = "phone_1.jpg"; + public static final String FJ_NAME_2 = "phone_panoramic_1.jpg"; + public static final String FJ_NAME_3 = "phone_video_1.mp4"; + public static final String FJ_NAME_4 = "photo_uav_1658133414992.jpg"; + public static final String FJ_NAME_5 = "photo_uav_1658133423647_panoramic.jpg"; + public static final String RELATIVE_PATH = "testData/"+DB_NAME; + public static final String RELATIVE_FJ_DIR = "testData/fj/"; + + private DataRepositories() { + + } + + public static DataRepositories getInstance() { + if (instance == null) { + synchronized (DataRepositories.class) { + instance = new DataRepositories(); + } + } + return instance; + } + + public void initData(@NonNull Context context) { + initDb(context); + File file = new File(Environment.getExternalStorageDirectory(),RELATIVE_PATH); + LandSurveyDatabase.init(context,file.getPath()); +// LandSurveyDatabase.getInstance().clearAllTables(); + initTestData(context); + } + + private void initTestData(@NonNull Context context) { + //测试扩展信息 + KZXXYSJ jbxx_dlbm = new KZXXYSJ(); + jbxx_dlbm.setBSM(1); + jbxx_dlbm.setTBLX("JCTB"); + jbxx_dlbm.setZDMC("DLBM"); + jbxx_dlbm.setZDBM("地类编码"); + jbxx_dlbm.setZDMS("地类编码"); + jbxx_dlbm.setZDLX("TEXT"); + jbxx_dlbm.setZDCD(20); + jbxx_dlbm.setSFBT("M"); + jbxx_dlbm.setKZXXLX("JBXX"); + + KZXXYSJ jbxx_dlmc = new KZXXYSJ(); + jbxx_dlmc.setBSM(2); + jbxx_dlmc.setTBLX("JCTB"); + jbxx_dlmc.setZDMC("DLMC"); + jbxx_dlmc.setZDBM("地类名称"); + jbxx_dlmc.setZDMS("地类名称"); + jbxx_dlmc.setZDLX("TEXT"); + jbxx_dlmc.setZDCD(20); + jbxx_dlmc.setSFBT("O"); + jbxx_dlmc.setKZXXLX("JBXX"); + + KZXXYSJ dcxx_bglx = new KZXXYSJ(); + dcxx_bglx.setBSM(3); + dcxx_bglx.setTBLX("JCTB"); + dcxx_bglx.setZDMC("BGLX"); + dcxx_bglx.setZDBM("变更类型"); + dcxx_bglx.setZDMS("变更类型"); + dcxx_bglx.setZDLX("TEXT"); + dcxx_bglx.setZDCD(20); + dcxx_bglx.setSFBT("O"); + dcxx_bglx.setKZXXLX("DCXX"); + + KZXXYSJ dcxx_bgfw = new KZXXYSJ(); + dcxx_bgfw.setBSM(4); + dcxx_bgfw.setTBLX("JCTB"); + dcxx_bgfw.setZDMC("BGFW"); + dcxx_bgfw.setZDBM("变更范围"); + dcxx_bgfw.setZDMS("变更范围"); + dcxx_bgfw.setZDLX("TEXT"); + dcxx_bgfw.setZDCD(20); + dcxx_bgfw.setSFBT("O"); + dcxx_bgfw.setKZXXLX("DCXX"); + + LandSurveyDatabase.getInstance().kzxxysjDao().insertKZXXYSJ(jbxx_dlbm,jbxx_dlmc,dcxx_bglx,dcxx_bgfw); + //测试地块信息 + TBJBXX tbjbxx = new TBJBXX(); + tbjbxx.setBSM("8fd575622ffd45ff8ae9fba0b9c5ec20"); + tbjbxx.setTBLX("JCTB"); + tbjbxx.setXZQDM("110101"); + tbjbxx.setXMC("余杭"); + tbjbxx.setTBBH("CS110101201600000100099"); + tbjbxx.setTBMC("1"); + tbjbxx.setTBMJ(9.43); + tbjbxx.setXZB(40498699.025); + tbjbxx.setYZB(3350604.784); + tbjbxx.setBZ(""); + + HashMap jbxxMap = new HashMap<>(); + jbxxMap.put("DLBM","03B2"); + jbxxMap.put("DLMC","工地草被"); + JSONObject jbxxKZXXJSON = new JSONObject(jbxxMap); + tbjbxx.setKZXX(jbxxKZXXJSON.toString()); + + tbjbxx.setTBFW("MULTIPOLYGON (((40498699.02535 3350604.7848, 40498697.04095 3350528.7169499993, 40498781.7078 3350530.70135, 40498780.3849 3350606.1077500004, 40498699.02535 3350604.7848)))"); + + LandSurveyDatabase.getInstance().tbjbxxDao().insertTBJBXX(tbjbxx); + //测试调查信息 + DCHSXX dchsxx = new DCHSXX(); + dchsxx.setDCRY("张三"); + dchsxx.setDCSJ("2022-10-14 10:12:13"); + HashMap dcxxMap = new HashMap<>(); + dcxxMap.put("BGFW","部分变更"); + dcxxMap.put("BGLX","0"); + JSONObject dcxxKZXXJson = new JSONObject(dcxxMap); + dchsxx.setKZXX(dcxxKZXXJson.toString()); + dchsxx.setWYHSQK("违法建筑"); + dchsxx.setTBBSM("8fd575622ffd45ff8ae9fba0b9c5ec20"); + LandSurveyDatabase.getInstance().dchsxxDao().insertDCHSXX(dchsxx); + + DBInfo dbInfo = new DBInfo(); + dbInfo.setCreatetime(TimeUtils.getNowString()); + dbInfo.setUpdatetime(TimeUtils.getNowString()); + dbInfo.setDescription("测试数据包"); + dbInfo.setCreateuser("admin"); + dbInfo.setVersion("1.0"); + LandSurveyDatabase.getInstance().dbInfoDao().insertDBInfo(dbInfo); + + JMXX jmxx = new JMXX(); + jmxx.setZSDM("1001"); + jmxx.setSZZS(TEST_CER); + jmxx.setZSBFJGDM(CERT_ORG_CODE); + jmxx.setZSBFJGGY(TEST_CERT_ORG_PUBLICKEY); + + LandSurveyDatabase.getInstance().jmxxDao().insertJMXX(jmxx); + //测试附件 + FJ fj_phone_normal = new FJ(); + + fj_phone_normal.setBSM("1"); + fj_phone_normal.setTBLX("JCTB"); + fj_phone_normal.setTBBSM("8fd575622ffd45ff8ae9fba0b9c5ec20"); + fj_phone_normal.setXZQDM("110101"); + fj_phone_normal.setFJMC("110101"); + fj_phone_normal.setFJLX("0"); + fj_phone_normal.setPSTZ("J"); + + File file = new File(Environment.getExternalStorageDirectory(),RELATIVE_FJ_DIR+"phone_1.jpg"); + fj_phone_normal.setFJ(FileIOUtils.readFile2BytesByChannel(file)); + try { + fj_phone_normal.setFJHXZ(SM3Utils.sm3(file)); + } catch (IOException e) { + e.printStackTrace(); + } + fj_phone_normal.setPSSJ("2022-10-18 15:42:56"); + //无人机时必填 +// fj_phone_normal.setJDGD(null); + fj_phone_normal.setLongitude(119.9854700); + fj_phone_normal.setLatitude(30.2776150); + fj_phone_normal.setPSFYJ(41d); + fj_phone_normal.setPSJD(239d); + fj_phone_normal.setPSHGJ(2d); + fj_phone_normal.setPSJJ(27d); + fj_phone_normal.setXDGD(1.50d); + fj_phone_normal.setFJYSKD(1920); + fj_phone_normal.setFJYSGD(1080); + fj_phone_normal.setPSRY("test"); + + //为视频时必填 +// fj_phone_normal.setSPKZXX(""); + fj_phone_normal.setZSDM("1001"); + //附件信息上链时返回的交易ID +// fj_phone_normal.setQKLDM(null); + //校验码 + StringBuffer content = new StringBuffer(); +// FJHXZ,PSSJ,Longitude,Latitude,PSFYJ,PSJD,PSHGJ,PSRY,ZSDM + content.append(fj_phone_normal.getFJHXZ()).append(","); + content.append(fj_phone_normal.getPSSJ()).append(","); + content.append(fj_phone_normal.getLongitude()).append(","); + content.append(fj_phone_normal.getLatitude()).append(","); + content.append(fj_phone_normal.getPSFYJ()).append(","); + content.append(fj_phone_normal.getPSJD()).append(","); + content.append(fj_phone_normal.getPSHGJ()).append(","); + content.append(fj_phone_normal.getPSRY()).append(","); + content.append(fj_phone_normal.getZSDM()); + String jym = Utils.makeJYM(content.toString(),Constants.TEST_PRIVATEKEY); + fj_phone_normal.setJYM(jym); + +// SM2SignVO verify = SM2SignVerUtils.VerifySignSM2(Util.hexStringToBytes(TEST_PUBLICKEY), SM3Utils.sm3(content.toString()).getBytes(StandardCharsets.UTF_8), Util.hexStringToBytes(jym)); +// System.out.println("验签得到的R值:"+verify.getVerify_r()); +// System.err.println("\n验签结果" +verify.isVerify()); + + FJ fj_phone_panoramic = new FJ(); + + fj_phone_panoramic.setBSM("2"); + fj_phone_panoramic.setTBLX("JCTB"); + fj_phone_panoramic.setTBBSM("8fd575622ffd45ff8ae9fba0b9c5ec21"); + fj_phone_panoramic.setXZQDM("110101"); + fj_phone_panoramic.setFJMC("110101"); + fj_phone_panoramic.setFJLX("2"); + fj_phone_panoramic.setPSTZ("J"); + + file = new File(Environment.getExternalStorageDirectory(),RELATIVE_FJ_DIR+"phone_panoramic_1.jpg"); + fj_phone_panoramic.setFJ(FileIOUtils.readFile2BytesByChannel(file)); + try { + fj_phone_panoramic.setFJHXZ(SM3Utils.sm3(file)); + } catch (IOException e) { + e.printStackTrace(); + } + fj_phone_panoramic.setPSSJ("2022:10:18 15:43:50"); + //无人机时必填 +// fj_phone_panoramic.setJDGD(null); + fj_phone_panoramic.setLongitude(119.9854813); + fj_phone_panoramic.setLatitude(30.2775860); + fj_phone_panoramic.setPSFYJ(26d); + fj_phone_panoramic.setPSJD(22d); + fj_phone_panoramic.setPSHGJ(-88d); + fj_phone_panoramic.setPSJJ(27d); + fj_phone_panoramic.setXDGD(1.50d); + fj_phone_panoramic.setFJYSKD(4096); + fj_phone_panoramic.setFJYSGD(2048); + fj_phone_panoramic.setPSRY("test"); + + //为视频时必填 +// fj_phone_panoramic.setSPKZXX(""); + fj_phone_panoramic.setZSDM("1001"); + //附件信息上链时返回的交易ID +// fj_phone_panoramic.setQKLDM(null); + //校验码 + content = new StringBuffer(); +// FJHXZ,PSSJ,Longitude,Latitude,PSFYJ,PSJD,PSHGJ,PSRY,ZSDM + content.append(fj_phone_panoramic.getFJHXZ()).append(","); + content.append(fj_phone_panoramic.getPSSJ()).append(","); + content.append(fj_phone_panoramic.getLongitude()).append(","); + content.append(fj_phone_panoramic.getLatitude()).append(","); + content.append(fj_phone_panoramic.getPSFYJ()).append(","); + content.append(fj_phone_panoramic.getPSJD()).append(","); + content.append(fj_phone_panoramic.getPSHGJ()).append(","); + content.append(fj_phone_panoramic.getPSRY()).append(","); + content.append(fj_phone_panoramic.getZSDM()); + fj_phone_panoramic.setJYM(Utils.makeJYM(content.toString(),Constants.TEST_PRIVATEKEY)); + + FJ fj_uav_normal = new FJ(); + + fj_uav_normal.setBSM("3"); + fj_uav_normal.setTBLX("JCTB"); + fj_uav_normal.setTBBSM("8fd575622ffd45ff8ae9fba0b9c5ec23"); + fj_uav_normal.setXZQDM("110101"); + fj_uav_normal.setFJMC("110101"); + fj_uav_normal.setFJLX("1"); + fj_uav_normal.setPSTZ("J"); + + file = new File(Environment.getExternalStorageDirectory(),RELATIVE_FJ_DIR+"photo_uav_1658133414992.jpg"); + fj_uav_normal.setFJ(FileIOUtils.readFile2BytesByChannel(file)); + try { + fj_uav_normal.setFJHXZ(SM3Utils.sm3(file)); + } catch (IOException e) { + e.printStackTrace(); + } + fj_uav_normal.setPSSJ("2022:07:18 16:35:21"); + //无人机时必填 + fj_uav_normal.setJDGD(-19d); + fj_uav_normal.setLongitude(119.9855061); + fj_uav_normal.setLatitude(30.2774821); + fj_uav_normal.setPSFYJ(-66d); + fj_uav_normal.setPSJD(337d); + fj_uav_normal.setPSHGJ(0d); + fj_uav_normal.setPSJJ(24d); + fj_uav_normal.setXDGD(111.00d); + fj_uav_normal.setFJYSKD(4000); + fj_uav_normal.setFJYSGD(2250); + fj_uav_normal.setPSRY("kmap"); + + //为视频时必填 +// fj_uav_normal.setSPKZXX(""); + fj_uav_normal.setZSDM("1001"); + //附件信息上链时返回的交易ID +// fj_uav_normal.setQKLDM(null); + //校验码 + content = new StringBuffer(); +// FJHXZ,PSSJ,Longitude,Latitude,PSFYJ,PSJD,PSHGJ,PSRY,ZSDM + content.append(fj_uav_normal.getFJHXZ()).append(","); + content.append(fj_uav_normal.getPSSJ()).append(","); + content.append(fj_uav_normal.getLongitude()).append(","); + content.append(fj_uav_normal.getLatitude()).append(","); + content.append(fj_uav_normal.getPSFYJ()).append(","); + content.append(fj_uav_normal.getPSJD()).append(","); + content.append(fj_uav_normal.getPSHGJ()).append(","); + content.append(fj_uav_normal.getPSRY()).append(","); + content.append(fj_uav_normal.getZSDM()); + fj_uav_normal.setJYM(Utils.makeJYM(content.toString(),Constants.TEST_PRIVATEKEY)); + + + FJ fj_uav_panoramic = new FJ(); + + fj_uav_panoramic.setBSM("4"); + fj_uav_panoramic.setTBLX("JCTB"); + fj_uav_panoramic.setTBBSM("8fd575622ffd45ff8ae9fba0b9c5ec24"); + fj_uav_panoramic.setXZQDM("110101"); + fj_uav_panoramic.setFJMC("110101"); + fj_uav_panoramic.setFJLX("3"); + fj_uav_panoramic.setPSTZ("J"); + + file = new File(Environment.getExternalStorageDirectory(),RELATIVE_FJ_DIR+"photo_uav_1658133423647_panoramic.jpg"); + fj_uav_panoramic.setFJ(FileIOUtils.readFile2BytesByChannel(file)); + try { + fj_uav_panoramic.setFJHXZ(SM3Utils.sm3(file)); + } catch (IOException e) { + e.printStackTrace(); + } + fj_uav_panoramic.setPSSJ("2022:07:18 16:36:44"); + //无人机时必填 + fj_uav_panoramic.setJDGD(-19d); + fj_uav_panoramic.setLongitude(119.9855061); + fj_uav_panoramic.setLatitude(30.2774821); + fj_uav_panoramic.setPSFYJ(-89d); + fj_uav_panoramic.setPSJD(337d); + fj_uav_panoramic.setPSHGJ(0d); + fj_uav_panoramic.setPSJJ(24d); + fj_uav_panoramic.setXDGD(112.00d); + fj_uav_panoramic.setFJYSKD(4096); + fj_uav_panoramic.setFJYSGD(2048); + fj_uav_panoramic.setPSRY("kmap"); + + //为视频时必填 +// fj_uav_panoramic.setSPKZXX(""); + fj_uav_panoramic.setZSDM("1001"); + //附件信息上链时返回的交易ID +// fj_uav_panoramic.setQKLDM(null); + //校验码 + content = new StringBuffer(); +// FJHXZ,PSSJ,Longitude,Latitude,PSFYJ,PSJD,PSHGJ,PSRY,ZSDM + content.append(fj_uav_panoramic.getFJHXZ()).append(","); + content.append(fj_uav_panoramic.getPSSJ()).append(","); + content.append(fj_uav_panoramic.getLongitude()).append(","); + content.append(fj_uav_panoramic.getLatitude()).append(","); + content.append(fj_uav_panoramic.getPSFYJ()).append(","); + content.append(fj_uav_panoramic.getPSJD()).append(","); + content.append(fj_uav_panoramic.getPSHGJ()).append(","); + content.append(fj_uav_panoramic.getPSRY()).append(","); + content.append(fj_uav_panoramic.getZSDM()); + fj_uav_panoramic.setJYM(Utils.makeJYM(content.toString(),Constants.TEST_PRIVATEKEY)); + + FJ fj_video = new FJ(); + fj_video.setBSM("5"); + fj_video.setTBLX("JCTB"); + fj_video.setTBBSM("8fd575622ffd45ff8ae9fba0b9c5ec25"); + fj_video.setXZQDM("110101"); + fj_video.setFJMC("110101"); + fj_video.setFJLX("4"); + fj_video.setPSTZ("J"); + + file = new File(Environment.getExternalStorageDirectory(),RELATIVE_FJ_DIR+"phone_video_1.mp4"); + fj_video.setFJ(FileIOUtils.readFile2BytesByChannel(file)); + try { + fj_video.setFJHXZ(SM3Utils.sm3(file)); + } catch (IOException e) { + e.printStackTrace(); + } + fj_video.setPSSJ("2022-10-18 15:43:09"); + //无人机时必填 +// fj_video.setJDGD(null); + fj_video.setLongitude(119.9854736); + fj_video.setLatitude(30.2776146); + fj_video.setPSFYJ(15d); + fj_video.setPSJD(230d); + fj_video.setPSHGJ(0d); + fj_video.setPSJJ(27d); + fj_video.setXDGD(1.50d); + fj_video.setFJYSKD(480); + fj_video.setFJYSGD(360); + fj_video.setPSRY("test"); + + //为视频时必填 + fj_video.setSPKZXX("[{\"position\":1,\"x\":119.9854736,\"y\":30.27761460,\"angel\":230,\"height\":1.5},{\"position\":2,\"x\":119.985474,\"y\":30.27761460,\"angel\":232,\"height\":1.5},{\"position\":3,\"x\":119.9854736,\"y\":30.27761460,\"angel\":220,\"height\":1.5},{\"position\":4,\"x\":119.9854736,\"y\":30.27761459,\"angel\":231,\"height\":1.5},{\"position\":5,\"x\":119.9854736,\"y\":30.27761459,\"angel\":237,\"height\":1.5},{\"position\":6,\"x\":119.9854736,\"y\":30.27761459,\"angel\":246,\"height\":1.5},{\"position\":7,\"x\":119.9854736,\"y\":30.27761460,\"angel\":235,\"height\":1.5},{\"position\":8,\"x\":119.9854736,\"y\":30.27761459,\"angel\":213,\"height\":1.5},{\"position\":9,\"x\":119.9854736,\"y\":30.27761459,\"angel\":254,\"height\":1.5}]"); + fj_video.setZSDM("1001"); + //附件信息上链时返回的交易ID +// fj_video.setQKLDM(null); + //校验码 + content = new StringBuffer(); +// FJHXZ,PSSJ,Longitude,Latitude,PSFYJ,PSJD,PSHGJ,PSRY,ZSDM + content.append(fj_video.getFJHXZ()).append(","); + content.append(fj_video.getPSSJ()).append(","); + content.append(fj_video.getLongitude()).append(","); + content.append(fj_video.getLatitude()).append(","); + content.append(fj_video.getPSFYJ()).append(","); + content.append(fj_video.getPSJD()).append(","); + content.append(fj_video.getPSHGJ()).append(","); + content.append(fj_video.getPSRY()).append(","); + content.append(fj_video.getZSDM()); + fj_video.setJYM(Utils.makeJYM(content.toString(),Constants.TEST_PRIVATEKEY)); + + + LandSurveyDatabase.getInstance().fjDao().insertFJ(fj_phone_normal,fj_phone_panoramic,fj_uav_normal,fj_uav_panoramic,fj_video); +// LandSurveyDatabase.getInstance().fjDao().insertFJ(fj_phone_normal,fj_phone_panoramic,fj_uav_normal); + + } + + public void initDb(@NonNull Context context) { + try { + InputStream is = context.getAssets().open(DB_NAME); + File file = new File(Environment.getExternalStorageDirectory(), RELATIVE_PATH); + if (!file.exists() || !file.isFile()) { + file.getParentFile().mkdir(); + FileIOUtils.writeFileFromIS(file,is); + } + + is = context.getAssets().open(FJ_NAME_1); + file = new File(Environment.getExternalStorageDirectory(), RELATIVE_FJ_DIR+FJ_NAME_1); + if (!file.exists() || !file.isFile()) { + file.getParentFile().mkdir(); + FileIOUtils.writeFileFromIS(file,is); + } + is = context.getAssets().open(FJ_NAME_2); + file = new File(Environment.getExternalStorageDirectory(), RELATIVE_FJ_DIR+FJ_NAME_2); + if (!file.exists() || !file.isFile()) { + file.getParentFile().mkdir(); + FileIOUtils.writeFileFromIS(file,is); + } + is = context.getAssets().open(FJ_NAME_3); + file = new File(Environment.getExternalStorageDirectory(), RELATIVE_FJ_DIR+FJ_NAME_3); + if (!file.exists() || !file.isFile()) { + file.getParentFile().mkdir(); + FileIOUtils.writeFileFromIS(file,is); + } + is = context.getAssets().open(FJ_NAME_4); + file = new File(Environment.getExternalStorageDirectory(), RELATIVE_FJ_DIR+FJ_NAME_4); + if (!file.exists() || !file.isFile()) { + file.getParentFile().mkdir(); + FileIOUtils.writeFileFromIS(file,is); + } + is = context.getAssets().open(FJ_NAME_5); + file = new File(Environment.getExternalStorageDirectory(), RELATIVE_FJ_DIR+FJ_NAME_5); + if (!file.exists() || !file.isFile()) { + file.getParentFile().mkdir(); + FileIOUtils.writeFileFromIS(file,is); + } + } catch (IOException e) { + e.printStackTrace(); + } finally { + } + } + + +} diff --git a/app/src/main/java/cn/org/landcloud/survey/data/FJDao.java b/app/src/main/java/cn/org/landcloud/survey/data/FJDao.java new file mode 100644 index 0000000..f6d3c79 --- /dev/null +++ b/app/src/main/java/cn/org/landcloud/survey/data/FJDao.java @@ -0,0 +1,52 @@ +package cn.org.landcloud.survey.data; + + +import androidx.room.Dao; +import androidx.room.Delete; +import androidx.room.Insert; +import androidx.room.OnConflictStrategy; +import androidx.room.Update; + +import java.util.List; + +import cn.org.landcloud.survey.data.bean.FJ; + + +@Dao +public interface FJDao { + + + /** + * 插入一条新的附件 + * 如插入时发生冲突,处理方式为插入一个新的对象。 + * @param fj + * @return + */ + @Insert(onConflict = OnConflictStrategy.REPLACE) + long insertFJ(FJ fj); + + @Update + int updateFJ(FJ fj); + + @Delete + int deleteFJ(FJ fj); + + @Insert(onConflict = OnConflictStrategy.REPLACE) + void insertFJ(FJ... fj); + + @Insert(onConflict = OnConflictStrategy.REPLACE) + void insertFJ(List fjs); + + @Update + void updateFJ(FJ... fj); + + @Update + void updateFJ(List fj); + + @Delete + void deleteFJ(FJ... fj); + + @Delete + void deleteFJ(List fj); + +} diff --git a/app/src/main/java/cn/org/landcloud/survey/data/JMXXDao.java b/app/src/main/java/cn/org/landcloud/survey/data/JMXXDao.java new file mode 100644 index 0000000..082238d --- /dev/null +++ b/app/src/main/java/cn/org/landcloud/survey/data/JMXXDao.java @@ -0,0 +1,54 @@ +package cn.org.landcloud.survey.data; + + +import androidx.room.Dao; +import androidx.room.Delete; +import androidx.room.Insert; +import androidx.room.OnConflictStrategy; +import androidx.room.Update; + +import java.util.List; + +import cn.org.landcloud.survey.data.bean.JMXX; +import cn.org.landcloud.survey.data.bean.KZXXYSJ; + + +@Dao +public interface JMXXDao { + + + /** + * 插入一条新的附件 + * 如插入时发生冲突,处理方式为插入一个新的对象。 + * + * @param kzxxysj + * @return + */ + @Insert(onConflict = OnConflictStrategy.REPLACE) + long insertJMXX(JMXX jmxx); + + @Update + int updateJMXX(JMXX jmxx); + + @Delete + int deleteJMXX(JMXX jmxx); + + @Insert(onConflict = OnConflictStrategy.REPLACE) + void insertKZXXYSJ(JMXX... jmxxs); + + @Insert(onConflict = OnConflictStrategy.REPLACE) + void insertJMXX(List jmxxList); + + @Update + void updateJMXX(JMXX... jmxxs); + + @Update + void updateJMXX(List jmxxList); + + @Delete + void deleteJMXX(JMXX... jmxxs); + + @Delete + void deleteJMXX(List jmxxList); + +} diff --git a/app/src/main/java/cn/org/landcloud/survey/data/KZXXYSJDao.java b/app/src/main/java/cn/org/landcloud/survey/data/KZXXYSJDao.java new file mode 100644 index 0000000..74282e1 --- /dev/null +++ b/app/src/main/java/cn/org/landcloud/survey/data/KZXXYSJDao.java @@ -0,0 +1,53 @@ +package cn.org.landcloud.survey.data; + + +import androidx.room.Dao; +import androidx.room.Delete; +import androidx.room.Insert; +import androidx.room.OnConflictStrategy; +import androidx.room.Update; + +import java.util.List; + +import cn.org.landcloud.survey.data.bean.KZXXYSJ; + + +@Dao +public interface KZXXYSJDao { + + + /** + * 插入一条新的附件 + * 如插入时发生冲突,处理方式为插入一个新的对象。 + * + * @param kzxxysj + * @return + */ + @Insert(onConflict = OnConflictStrategy.REPLACE) + long insertKZXXYSJ(KZXXYSJ kzxxysj); + + @Update + int updateKZXXYSJ(KZXXYSJ kzxxysj); + + @Delete + int deleteKZXXYSJ(KZXXYSJ kzxxysj); + + @Insert(onConflict = OnConflictStrategy.REPLACE) + void insertKZXXYSJ(KZXXYSJ... kzxxysjs); + + @Insert(onConflict = OnConflictStrategy.REPLACE) + void insertKZXXYSJ(List kzxxysjList); + + @Update + void updateKZXXYSJ(KZXXYSJ... kzxxysjs); + + @Update + void updateKZXXYSJ(List kzxxysjList); + + @Delete + void deleteKZXXYSJ(KZXXYSJ... kzxxysjs); + + @Delete + void deleteKZXXYSJ(List kzxxysjList); + +} diff --git a/app/src/main/java/cn/org/landcloud/survey/data/LandSurveyDatabase.java b/app/src/main/java/cn/org/landcloud/survey/data/LandSurveyDatabase.java new file mode 100644 index 0000000..80edee7 --- /dev/null +++ b/app/src/main/java/cn/org/landcloud/survey/data/LandSurveyDatabase.java @@ -0,0 +1,83 @@ +package cn.org.landcloud.survey.data; + + +import android.content.Context; +import android.text.TextUtils; + +import androidx.room.Database; +import androidx.room.Room; +import androidx.room.RoomDatabase; + +import cn.org.landcloud.survey.data.bean.DBInfo; +import cn.org.landcloud.survey.data.bean.DCHSXX; +import cn.org.landcloud.survey.data.bean.FJ; +import cn.org.landcloud.survey.data.bean.JMXX; +import cn.org.landcloud.survey.data.bean.KZXXYSJ; +import cn.org.landcloud.survey.data.bean.TBJBXX; + +@Database(entities = {DBInfo.class, DCHSXX.class, FJ.class, TBJBXX.class, KZXXYSJ.class, JMXX.class}, + version = 2, exportSchema = false) +public abstract class LandSurveyDatabase extends RoomDatabase { + + public static final String TABLE_NAME = "WYHCFJ"; + public static final String COLUMN_NAME_BSM = "F_ID"; + public static final String COLUMN_NAME_CONTENT = "FJ"; + + private static String sDbPath = null; + + private static volatile LandSurveyDatabase INSTANCE = null; + + private static Context mContext; + + /** + * 初始化AppDatabase参数 + * + * @param context 上下文引用 + * @param dbPath 数据库路径 + */ + public static void init(Context context, String dbPath) { + mContext = context; + sDbPath = dbPath; + if (INSTANCE != null) { + INSTANCE.close(); + INSTANCE = null; + } + } + + + public static LandSurveyDatabase getInstance() { + if (INSTANCE == null) { + synchronized (LandSurveyDatabase.class) { + if (INSTANCE == null) { + INSTANCE = Room + .databaseBuilder(mContext.getApplicationContext(), LandSurveyDatabase.class, sDbPath) + .allowMainThreadQueries() + .build(); + } + + } + } + return (INSTANCE); + } + + public void destroy() { + if (INSTANCE != null) { + INSTANCE.close(); + INSTANCE = null; + } + } + + public abstract DBInfoDao dbInfoDao(); + + public abstract DCHSXXDao dchsxxDao(); + + public abstract FJDao fjDao(); + + public abstract KZXXYSJDao kzxxysjDao(); + + public abstract TBJBXXDao tbjbxxDao(); + + public abstract JMXXDao jmxxDao(); + + +} diff --git a/app/src/main/java/cn/org/landcloud/survey/data/TBJBXXDao.java b/app/src/main/java/cn/org/landcloud/survey/data/TBJBXXDao.java new file mode 100644 index 0000000..749e109 --- /dev/null +++ b/app/src/main/java/cn/org/landcloud/survey/data/TBJBXXDao.java @@ -0,0 +1,54 @@ +package cn.org.landcloud.survey.data; + + +import androidx.room.Dao; +import androidx.room.Delete; +import androidx.room.Insert; +import androidx.room.OnConflictStrategy; +import androidx.room.Update; + +import java.util.List; + +import cn.org.landcloud.survey.data.bean.KZXXYSJ; +import cn.org.landcloud.survey.data.bean.TBJBXX; + + +@Dao +public interface TBJBXXDao { + + + /** + * 插入一条新的附件 + * 如插入时发生冲突,处理方式为插入一个新的对象。 + * + * @param tbjbxx + * @return + */ + @Insert(onConflict = OnConflictStrategy.REPLACE) + long insertTBJBXX(TBJBXX tbjbxx); + + @Update + int updateTBJBXX(TBJBXX tbjbxx); + + @Delete + int deleteTBJBXX(TBJBXX tbjbxx); + + @Insert(onConflict = OnConflictStrategy.REPLACE) + void insertTBJBXX(TBJBXX... tbjbxx); + + @Insert(onConflict = OnConflictStrategy.REPLACE) + void insertTBJBXX(List tbjbxxs); + + @Update + void updateTBJBXX(TBJBXX... tbjbxx); + + @Update + void updateTBJBXX(List tbjbxx); + + @Delete + void deleteTBJBXX(TBJBXX... tbjbxx); + + @Delete + void deleteTBJBXX(List tbjbxx); + +} diff --git a/app/src/main/java/cn/org/landcloud/survey/data/bean/DBInfo.java b/app/src/main/java/cn/org/landcloud/survey/data/bean/DBInfo.java new file mode 100644 index 0000000..38e175b --- /dev/null +++ b/app/src/main/java/cn/org/landcloud/survey/data/bean/DBInfo.java @@ -0,0 +1,87 @@ +package cn.org.landcloud.survey.data.bean; + +import androidx.annotation.NonNull; +import androidx.room.Entity; +import androidx.room.PrimaryKey; + +import java.io.Serializable; + +@Entity(tableName = "DB_INFO") +public class DBInfo implements Serializable { + + /** + * 版本号 + * 当前db包的格式规范的版本号,当前标准的版本为固定值1.0 + */ + @PrimaryKey + @NonNull + private String version; + + /** + * 创建时间: + * Db包创建时间,格式:yyyy-MM-dd HH:mm:ss + */ + private String createtime; + + /** + * 修改时间: + * Db包修改时间,格式:yyyy-MM-dd HH:mm:ss + */ + private String updatetime; + + /** + * 生成人员: + * Db包创建人员 + */ + private String createuser; + + /** + * 描述信息: + * Db包的描述 + */ + private String description; + + public DBInfo() { + } + + public String getVersion() { + return version; + } + + public void setVersion(String version) { + this.version = version; + } + + public String getCreatetime() { + return createtime; + } + + public void setCreatetime(String createtime) { + this.createtime = createtime; + } + + public String getUpdatetime() { + return updatetime; + } + + public void setUpdatetime(String updatetime) { + this.updatetime = updatetime; + } + + public String getCreateuser() { + return createuser; + } + + public void setCreateuser(String createuser) { + this.createuser = createuser; + } + + public String getDescription() { + return description; + } + + public void setDescription(String description) { + this.description = description; + } + +} diff --git a/app/src/main/java/cn/org/landcloud/survey/data/bean/DCHSXX.java b/app/src/main/java/cn/org/landcloud/survey/data/bean/DCHSXX.java new file mode 100644 index 0000000..b53002e --- /dev/null +++ b/app/src/main/java/cn/org/landcloud/survey/data/bean/DCHSXX.java @@ -0,0 +1,89 @@ +package cn.org.landcloud.survey.data.bean; + +import androidx.annotation.NonNull; +import androidx.room.Entity; +import androidx.room.PrimaryKey; + +import java.io.Serializable; + +/** + * 调查核实信息表 + */ +@Entity(tableName = "DCHSXX") +public class DCHSXX implements Serializable { + + /** + * 地块标识码: + * 主键,地块基本信息表中的地块标识码 + */ + @PrimaryKey + @NonNull + private String TBBSM; + + /** + * 外业核实情况 + */ + private String WYHSQK; + + /** + * 扩展信息: + * 扩展信息,json字符串。根据元数据表进行描述 + */ + private String KZXX; + + /** + * 调查人员 + */ + @NonNull + private String DCRY; + + /** + * 调查时间: + * 精确到秒,格式:yyyy-MM-dd HH:mm:ss + */ + @NonNull + private String DCSJ; + + public DCHSXX() { + } + + public String getTBBSM() { + return TBBSM; + } + + public void setTBBSM(String TBBSM) { + this.TBBSM = TBBSM; + } + + public String getWYHSQK() { + return WYHSQK; + } + + public void setWYHSQK(String WYHSQK) { + this.WYHSQK = WYHSQK; + } + + public String getKZXX() { + return KZXX; + } + + public void setKZXX(String KZXX) { + this.KZXX = KZXX; + } + + public String getDCRY() { + return DCRY; + } + + public void setDCRY(String DCRY) { + this.DCRY = DCRY; + } + + public String getDCSJ() { + return DCSJ; + } + + public void setDCSJ(String DCSJ) { + this.DCSJ = DCSJ; + } +} diff --git a/app/src/main/java/cn/org/landcloud/survey/data/bean/FJ.java b/app/src/main/java/cn/org/landcloud/survey/data/bean/FJ.java new file mode 100644 index 0000000..b705a30 --- /dev/null +++ b/app/src/main/java/cn/org/landcloud/survey/data/bean/FJ.java @@ -0,0 +1,395 @@ +package cn.org.landcloud.survey.data.bean; + +import androidx.annotation.NonNull; +import androidx.room.Entity; +import androidx.room.PrimaryKey; + +import java.io.Serializable; + +/** + * 附件表实体类 + */ +@Entity(tableName = "FJ") +public class FJ implements Serializable { + + /** + * 标识码,主键 + */ + @PrimaryKey + @NonNull + private String BSM; + + /** + * 地块类型 + */ + @NonNull + private String TBLX; + + /** + * 地块标识码: + * 地块基本信息表中的标识码字段 + */ + @NonNull + private String TBBSM; + + /** + * 县级行政区代码: + * 6位县级行政区代码 + */ + @NonNull + private String XZQDM; + + /** + * 附件名称: + * 需带格式后缀,如*.jpg、*.png、*.mp4等 + */ + private String FJMC; + + /** + * 附件类型: + * 0:手机照片;1:无人机照片;2:手机全景;3:无人机全景;4:手机视频。 + * 默认为0 + */ + @NonNull + private String FJLX; + + /** + * 拍摄特征: + * Y:远景 + * J:近景 + * T:局部特征 + */ + @NonNull + private String PSTZ; + + /** + * 附件: + * 文件内容的二进制存储 + */ + @NonNull + private byte[] FJ; + + /** + * 附件哈希值: + * 附件的哈希值是对文件的内容采用国密SM3计算哈希值 + */ + @NonNull + private String FJHXZ; + + /** + * 拍摄时间: + * 精确到秒,格式:yyyy-MM-dd HH:mm:ss + */ + @NonNull + private String PSSJ; + + /** + * 拍摄相对高度: + * 单位为米,保留2位小数。当为无人机拍摄时高度为无人机的相对高度,当为手机拍摄时一般为拍摄人员的身高 + */ + @NonNull + private Double XDGD; + + /** + * 拍摄绝对高度: + * 拍摄点相对海平面的高度,单位为米,保留2位小数。当为无人机拍摄时必填 + */ + private Double JDGD; + + /** + * 拍摄点经度: + * CGCS2000球面坐标,保留7位小数 + */ + @NonNull + private Double Longitude; + + /** + * 拍摄点纬度: + * CGCS2000球面坐标,保留7位小数 + */ + @NonNull + private Double Latitude; + + /** + * 拍摄俯仰角: + * 俯仰角(pitch),无人机取值一般为[-90,0]手机取值为[-180,180],上翻为正由0至180,下翻为负由0至-180。无人机一般用相机的角度代替。 + */ + @NonNull + private Double PSFYJ; + + /** + * 拍摄角度: + * 方向角(yaw),值域范围[0,360],正北为0,顺时针方向递增至360 + */ + @NonNull + private Double PSJD; + + /** + * 拍摄横滚角: + * 横滚角(roll),值域范围[-180,180],向右滚为正由0至180,左滚为负0至-180。无人机为0 + */ + @NonNull + private Double PSHGJ; + + /** + * 拍摄焦距: + * 35mm等效焦距,单位mm,当附件类型为[0:手机照片]、[1:无人机照片]时必填。 + */ + private Double PSJJ; + + /** + * 附件原始宽度: + * 照片压缩前的原始分辨率-宽,当附件类型为[0:手机照片]、[1:无人机照片]时必填。 + */ + private Integer FJYSKD; + + /** + * 附件原始高度: + * 照片压缩前的原始分辨率-高,当附件类型为[0:手机照片]、[1:无人机照片]时必填。 + */ + private Integer FJYSGD; + + /** + * 拍摄人员: + * 拍照人员的姓名 + */ + @NonNull + private String PSRY; + + /** + * 视频扩展信息: + * JSON字符串,记录视频拍摄每秒的位置、方向等信息。当附件类型为[4:手机视频]时必填。 + * [ + * {position:时间,x:经度,y:纬度,angel:方位角,height:高度}, + * {position:时间,x:经度,y:纬度,angel:方位角,height:高度}, + * {position:时间,x:经度,y:纬度,angel:方位角,height:高度} + * ] + * 其中x,y经纬度为2000球面坐标系,保留7位小数,position为视频的时间位置,单位秒,方位角为度,height为高度,单位为米,保留2位小数;angel为方位角,为手机的镜头的方向,通过yaw、pitch、roll三个值综合计算得出,正北为0,顺时针旋转到360。 + * 注:当附件类型为视频时,相关参数为拍摄开始时的参数。 + */ + private String SPKZXX; + + /** + * 证书代码: + * 参考加密信息表证书代码 + */ + @NonNull + private String ZSDM; + + /** + * 区块链代码: + * 附件信息上链时返回的交易ID + */ + private String QKLDM; + + /** + * 校验码: + * 用于校验数据的真伪,通过上面的信息 + */ + @NonNull + private String JYM; + + + public FJ() { + } + + public String getBSM() { + return BSM; + } + + public void setBSM(String BSM) { + this.BSM = BSM; + } + + public String getTBLX() { + return TBLX; + } + + public void setTBLX(String TBLX) { + this.TBLX = TBLX; + } + + public String getTBBSM() { + return TBBSM; + } + + public void setTBBSM(String TBBSM) { + this.TBBSM = TBBSM; + } + + public String getXZQDM() { + return XZQDM; + } + + public void setXZQDM(String XZQDM) { + this.XZQDM = XZQDM; + } + + public String getFJMC() { + return FJMC; + } + + public void setFJMC(String FJMC) { + this.FJMC = FJMC; + } + + public String getFJLX() { + return FJLX; + } + + public void setFJLX(String FJLX) { + this.FJLX = FJLX; + } + + public String getPSTZ() { + return PSTZ; + } + + public void setPSTZ(String PSTZ) { + this.PSTZ = PSTZ; + } + + public byte[] getFJ() { + return FJ; + } + + public void setFJ(byte[] FJ) { + this.FJ = FJ; + } + + public String getFJHXZ() { + return FJHXZ; + } + + public void setFJHXZ(String FJHXZ) { + this.FJHXZ = FJHXZ; + } + + public String getPSSJ() { + return PSSJ; + } + + public void setPSSJ(String PSSJ) { + this.PSSJ = PSSJ; + } + + public Double getXDGD() { + return XDGD; + } + + public void setXDGD(Double XDGD) { + this.XDGD = XDGD; + } + + public Double getJDGD() { + return JDGD; + } + + public void setJDGD(Double JDGD) { + this.JDGD = JDGD; + } + + public Double getLongitude() { + return Longitude; + } + + public void setLongitude(Double longitude) { + Longitude = longitude; + } + + public Double getLatitude() { + return Latitude; + } + + public void setLatitude(Double latitude) { + Latitude = latitude; + } + + public Double getPSFYJ() { + return PSFYJ; + } + + public void setPSFYJ(Double PSFYJ) { + this.PSFYJ = PSFYJ; + } + + public Double getPSJD() { + return PSJD; + } + + public void setPSJD(Double PSJD) { + this.PSJD = PSJD; + } + + public Double getPSHGJ() { + return PSHGJ; + } + + public void setPSHGJ(Double PSHGJ) { + this.PSHGJ = PSHGJ; + } + + public Double getPSJJ() { + return PSJJ; + } + + public void setPSJJ(Double PSJJ) { + this.PSJJ = PSJJ; + } + + public Integer getFJYSKD() { + return FJYSKD; + } + + public void setFJYSKD(Integer FJYSKD) { + this.FJYSKD = FJYSKD; + } + + public Integer getFJYSGD() { + return FJYSGD; + } + + public void setFJYSGD(Integer FJYSGD) { + this.FJYSGD = FJYSGD; + } + + public String getPSRY() { + return PSRY; + } + + public void setPSRY(String PSRY) { + this.PSRY = PSRY; + } + + public String getSPKZXX() { + return SPKZXX; + } + + public void setSPKZXX(String SPKZXX) { + this.SPKZXX = SPKZXX; + } + + public String getZSDM() { + return ZSDM; + } + + public void setZSDM(String ZSDM) { + this.ZSDM = ZSDM; + } + + public String getQKLDM() { + return QKLDM; + } + + public void setQKLDM(String QKLDM) { + this.QKLDM = QKLDM; + } + + public String getJYM() { + return JYM; + } + + public void setJYM(String JYM) { + this.JYM = JYM; + } +} diff --git a/app/src/main/java/cn/org/landcloud/survey/data/bean/JMXX.java b/app/src/main/java/cn/org/landcloud/survey/data/bean/JMXX.java new file mode 100644 index 0000000..2262606 --- /dev/null +++ b/app/src/main/java/cn/org/landcloud/survey/data/bean/JMXX.java @@ -0,0 +1,91 @@ +package cn.org.landcloud.survey.data.bean; + +import androidx.annotation.NonNull; +import androidx.room.Entity; +import androidx.room.PrimaryKey; + +import java.io.Serializable; + +@Entity(tableName = "JMXX") +public class JMXX implements Serializable { + + /** + * 证书代码: + * 主键,在证书颁发时生成 + */ + @PrimaryKey + @NonNull + private String ZSDM; + + /** + * 数字证书: + * 数字证书文件的内容,base64编码的字符串 + */ + @NonNull + private String SZZS; + + /** + * 证书颁发机构代码: + * 颁发证书机构的统一信用代码 + */ + @NonNull + private String ZSBFJGDM; + + /** + * 证书颁发机构公钥: + * 颁发证书机构的公开公钥,用于验证和解密数字证书 + */ + private String ZSBFJGGY; + + /** + * 区块链访问地址: + * 区块链访问接口根地址 + */ + private String QKLFWDZ; + + public JMXX() { + } + + @NonNull + public String getZSDM() { + return ZSDM; + } + + public void setZSDM(@NonNull String ZSDM) { + this.ZSDM = ZSDM; + } + + @NonNull + public String getSZZS() { + return SZZS; + } + + public void setSZZS(@NonNull String SZZS) { + this.SZZS = SZZS; + } + + @NonNull + public String getZSBFJGDM() { + return ZSBFJGDM; + } + + public void setZSBFJGDM(@NonNull String ZSBFJGDM) { + this.ZSBFJGDM = ZSBFJGDM; + } + + public String getZSBFJGGY() { + return ZSBFJGGY; + } + + public void setZSBFJGGY(String ZSBFJGGY) { + this.ZSBFJGGY = ZSBFJGGY; + } + + public String getQKLFWDZ() { + return QKLFWDZ; + } + + public void setQKLFWDZ(String QKLFWDZ) { + this.QKLFWDZ = QKLFWDZ; + } +} diff --git a/app/src/main/java/cn/org/landcloud/survey/data/bean/KZXXYSJ.java b/app/src/main/java/cn/org/landcloud/survey/data/bean/KZXXYSJ.java new file mode 100644 index 0000000..25d62a4 --- /dev/null +++ b/app/src/main/java/cn/org/landcloud/survey/data/bean/KZXXYSJ.java @@ -0,0 +1,166 @@ +package cn.org.landcloud.survey.data.bean; + +import androidx.annotation.NonNull; +import androidx.room.ColumnInfo; +import androidx.room.Entity; +import androidx.room.PrimaryKey; + +import java.io.Serializable; + + +/** + * 扩展信息元数据表 + */ +@Entity(tableName = "KZXXYSJ") +public class KZXXYSJ implements Serializable { + + /** + * 标识码: + * 主键 + */ + @PrimaryKey(autoGenerate = false) + @NonNull + private Integer BSM; + + /** + * 地块类型: + * 地块类型,例如:JCTB,SSNYD + */ + @NonNull + private String TBLX; + + /** + * 字段名称 + */ + @NonNull + private String ZDMC; + + /** + * 字段别名,字段的别名,一般是中文名称 + */ + @NonNull + private String ZDBM; + + /** + * 字段描述: + * 字段的中文描述 + */ + private String ZDMS; + + /** + * 字段类型: + * INTEGER:整数、TEXT:文本、REAL:数字 + */ + @NonNull + private String ZDLX; + + /** + * 字段长度 + */ + private Integer ZDCD; + + /** + * 是否必填: + * 是否必填。 Y:是,N:否 + */ + @NonNull + private String SFBT; + + /** + * 数据字典: + * 当字段类型为DIC时,该字段必填, + * 具体格式如下:[{code:”01”,description:”字典值1的描述”},{code:”02”,description:”字典值2的描述”},{code:”03”,description:”字典值3的描述”}],其中code为字典值,description为字典值的描述,两者都是文本类型;当字典值可多选时,对应值用英文逗号拼接,例如:”03,04”。 + */ + private String SJZD; + + /** + * 扩展信息类型: + * JBXX:基本信息的扩展信息字段 + * DCXX:调查信息扩展信息字段 + */ + @NonNull + private String KZXXLX; + + public KZXXYSJ() { + } + + public Integer getBSM() { + return BSM; + } + + public void setBSM(Integer BSM) { + this.BSM = BSM; + } + + public String getTBLX() { + return TBLX; + } + + public void setTBLX(String TBLX) { + this.TBLX = TBLX; + } + + public String getZDMC() { + return ZDMC; + } + + public void setZDMC(String ZDMC) { + this.ZDMC = ZDMC; + } + + public String getZDMS() { + return ZDMS; + } + + public void setZDMS(String ZDMS) { + this.ZDMS = ZDMS; + } + + public String getZDLX() { + return ZDLX; + } + + public void setZDLX(String ZDLX) { + this.ZDLX = ZDLX; + } + + public Integer getZDCD() { + return ZDCD; + } + + public void setZDCD(Integer ZDCD) { + this.ZDCD = ZDCD; + } + + public String getSFBT() { + return SFBT; + } + + public void setSFBT(String SFBT) { + this.SFBT = SFBT; + } + + public String getKZXXLX() { + return KZXXLX; + } + + public void setKZXXLX(String KZXXLX) { + this.KZXXLX = KZXXLX; + } + + public String getSJZD() { + return SJZD; + } + + public void setSJZD(String SJZD) { + this.SJZD = SJZD; + } + + public String getZDBM() { + return ZDBM; + } + + public void setZDBM(String ZDBM) { + this.ZDBM = ZDBM; + } +} diff --git a/app/src/main/java/cn/org/landcloud/survey/data/bean/TBJBXX.java b/app/src/main/java/cn/org/landcloud/survey/data/bean/TBJBXX.java new file mode 100644 index 0000000..9967c75 --- /dev/null +++ b/app/src/main/java/cn/org/landcloud/survey/data/bean/TBJBXX.java @@ -0,0 +1,192 @@ +package cn.org.landcloud.survey.data.bean; + +import androidx.annotation.NonNull; +import androidx.room.Entity; +import androidx.room.Index; +import androidx.room.PrimaryKey; + +import java.io.Serializable; + +/** + * 地块基本信息表 + */ +@Entity(tableName = "TBJBXX",indices = {@Index(name = "uidx_tbjbxx_tblx_xzqdm_tbbh", value = {"TBLX","XZQDM","TBBH"} ,unique = true)}) +public class TBJBXX implements Serializable { + + /** + * 标识码: + * 地块标识码。主键,全局唯一,建议使用GUID + */ + @NonNull + @PrimaryKey + private String BSM; + + /** + * 地块类型 + */ + @NonNull + private String TBLX; + + /** + * 县级行政区代码 + */ + @NonNull + private String XZQDM; + + /** + * 县级行政区名称 + */ + @NonNull + private String XMC; + + /** + * 地块编号: + * 区县唯一 + */ + @NonNull + private String TBBH; + + /** + * 地块名称 + */ + private String TBMC; + + /** + * 地块面积: + * 单位:亩,保留2位小数 + */ + @NonNull + private double TBMJ; + + /** + * X坐标: + * 投影参考为:CGCS2000平面坐标,含带号,保留3位小数 + */ + @NonNull + private double XZB; + + /** + * Y坐标: + * 投影参考为:CGCS2000平面坐标,含带号,保留3位小数 + */ + @NonNull + private double YZB; + + /** + * 备注: + * 选填,样本地类编码 + */ + private String BZ; + + /** + * 扩展信息: + * 扩展信息,json字符串。根据元数据表进行描述 + */ + private String KZXX; + + /** + * 地块范围: + * 地块边界,标准WKT格式,投影参考为:CGCS2000平面坐标,带带号 + */ + @NonNull + private String TBFW; + + public TBJBXX() { + } + + public String getBSM() { + return BSM; + } + + public void setBSM(String BSM) { + this.BSM = BSM; + } + + public String getTBLX() { + return TBLX; + } + + public void setTBLX(String TBLX) { + this.TBLX = TBLX; + } + + public String getXZQDM() { + return XZQDM; + } + + public void setXZQDM(String XZQDM) { + this.XZQDM = XZQDM; + } + + public String getXMC() { + return XMC; + } + + public void setXMC(String XMC) { + this.XMC = XMC; + } + + public String getTBBH() { + return TBBH; + } + + public void setTBBH(String TBBH) { + this.TBBH = TBBH; + } + + public String getTBMC() { + return TBMC; + } + + public void setTBMC(String TBMC) { + this.TBMC = TBMC; + } + + public double getTBMJ() { + return TBMJ; + } + + public void setTBMJ(double TBMJ) { + this.TBMJ = TBMJ; + } + + public double getXZB() { + return XZB; + } + + public void setXZB(double XZB) { + this.XZB = XZB; + } + + public double getYZB() { + return YZB; + } + + public void setYZB(double YZB) { + this.YZB = YZB; + } + + public String getBZ() { + return BZ; + } + + public void setBZ(String BZ) { + this.BZ = BZ; + } + + public String getKZXX() { + return KZXX; + } + + public void setKZXX(String KZXX) { + this.KZXX = KZXX; + } + + public String getTBFW() { + return TBFW; + } + + public void setTBFW(String TBFW) { + this.TBFW = TBFW; + } +} diff --git a/app/src/main/java/cn/org/landcloud/survey/util/CloseUtils.java b/app/src/main/java/cn/org/landcloud/survey/util/CloseUtils.java new file mode 100644 index 0000000..6688871 --- /dev/null +++ b/app/src/main/java/cn/org/landcloud/survey/util/CloseUtils.java @@ -0,0 +1,54 @@ +package cn.org.landcloud.survey.util; + +import java.io.Closeable; +import java.io.IOException; + +/** + *
+ *     author: Blankj
+ *     blog  : http://blankj.com
+ *     time  : 2016/10/09
+ *     desc  : 关闭相关工具类
+ * 
+ */ +public final class CloseUtils { + + private CloseUtils() { + throw new UnsupportedOperationException("u can't instantiate me..."); + } + + /** + * 关闭IO + * + * @param closeables closeables + */ + public static void closeIO(final Closeable... closeables) { + if (closeables == null) return; + for (Closeable closeable : closeables) { + if (closeable != null) { + try { + closeable.close(); + } catch (IOException e) { + e.printStackTrace(); + } + } + } + } + + /** + * 安静关闭IO + * + * @param closeables closeables + */ + public static void closeIOQuietly(final Closeable... closeables) { + if (closeables == null) return; + for (Closeable closeable : closeables) { + if (closeable != null) { + try { + closeable.close(); + } catch (IOException ignored) { + } + } + } + } +} diff --git a/app/src/main/java/cn/org/landcloud/survey/util/Constants.java b/app/src/main/java/cn/org/landcloud/survey/util/Constants.java new file mode 100644 index 0000000..4967cb9 --- /dev/null +++ b/app/src/main/java/cn/org/landcloud/survey/util/Constants.java @@ -0,0 +1,10 @@ +package cn.org.landcloud.survey.util; + +public class Constants { + + public static final String TEST_CER = "eyJjZXJ0Y29kZSI6IjEwMDEiLCJjZXJ0b3JnY29kZSI6IjEyMTAwMDAwNDAwMDEwMzk4UCIsImNlcnRvcmduYW1lIjoi5Lit5Zu95Zu95Zyf5YuY5rWL6KeE5YiS6ZmiIiwiZXhwaXJhdGlvbiI6IjE2OTcyNjkwNTEiLCJzaWduIjoiMzA0NDAyMjAxMkY5MThBRDdBODdEMTQ4MEU4ODZCMzlGOTQ3OTkxQjRFMUExQzBDNUM2MEU3QTVFRTM0M0Y1Rjg2QUE2QjE3MDIyMDM1M0I4Q0ZDQ0QyMjQ0QzM4NDRFMTc5QjM4OEY3ODIwMTBFRjE2RTRBMENFNTU5MDUzM0M3ODA0MjhBNTMyNjEiLCJvcmdjb2RlIjoiOTEzMzAxMTA2Nzk4ODU5NDAxIiwib3JnbmFtZSI6IuadreW3nuS7iuWlpeS/oeaBr+enkeaKgOiCoeS7veaciemZkOWFrOWPuCIsInB1YmxpY2tleSI6IjA0NzgyOEQ1NDY2QUI2QUYyMUZEODUyOEE5MDE2MjJBRTEwMEEzRUQ4MEUyQUZFRkFBMDkzQkVERjM2NjJDNTMyNzMwNURBQTBBODUzNzcwQkEwNjA1RjYyNjZCMDU1MzVFQ0NDNzc0N0JBQTEyMkYxODVDNDdEOUY2NUU3NEU2MEMifQ=="; + public static final String TEST_PRIVATEKEY= "00D7D395E6093C63A50A0370D5F6CD89964AB148A846EA96C9969AF08EC1E97513"; + public static final String TEST_PUBLICKEY= "047828D5466AB6AF21FD8528A901622AE100A3ED80E2AFEFAA093BEDF3662C5327305DAA0A853770BA0605F6266B05535ECCC7747BAA122F185C47D9F65E74E60C"; + public static final String TEST_CERT_ORG_PUBLICKEY= "048D9B68E8DECD33A19A73F87169BB4A65BFE557AA1F58462BAF5D63EFBC5EE5385D1184C3B2A5A0D6EE2ED401182D0E6AF362DCAA8931231399D941AD318D21AD"; + public static final String CERT_ORG_CODE = "12100000400010398P"; +} diff --git a/app/src/main/java/cn/org/landcloud/survey/util/FileIOUtils.java b/app/src/main/java/cn/org/landcloud/survey/util/FileIOUtils.java new file mode 100644 index 0000000..2fd3c32 --- /dev/null +++ b/app/src/main/java/cn/org/landcloud/survey/util/FileIOUtils.java @@ -0,0 +1,707 @@ +package cn.org.landcloud.survey.util; + +import java.io.BufferedOutputStream; +import java.io.BufferedReader; +import java.io.BufferedWriter; +import java.io.ByteArrayOutputStream; +import java.io.File; +import java.io.FileInputStream; +import java.io.FileOutputStream; +import java.io.FileWriter; +import java.io.IOException; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.io.OutputStream; +import java.io.RandomAccessFile; +import java.nio.ByteBuffer; +import java.nio.MappedByteBuffer; +import java.nio.channels.FileChannel; +import java.util.ArrayList; +import java.util.List; + +import cn.org.landcloud.survey.util.CloseUtils; + +/** + *
+ *     author: Blankj
+ *     blog  : http://blankj.com
+ *     time  : 2017/06/22
+ *     desc  : 文件读写相关工具类
+ * 
+ */ +public final class FileIOUtils { + + private FileIOUtils() { + throw new UnsupportedOperationException("u can't instantiate me..."); + } + + private static final String LINE_SEP = System.getProperty("line.separator"); + + private static int sBufferSize = 8192; + + /** + * 将输入流写入文件 + * + * @param filePath 路径 + * @param is 输入流 + * @return {@code true}: 写入成功
{@code false}: 写入失败 + */ + public static boolean writeFileFromIS(final String filePath, final InputStream is) { + return writeFileFromIS(getFileByPath(filePath), is, false); + } + + /** + * 将输入流写入文件 + * + * @param filePath 路径 + * @param is 输入流 + * @param append 是否追加在文件末 + * @return {@code true}: 写入成功
{@code false}: 写入失败 + */ + public static boolean writeFileFromIS(final String filePath, final InputStream is, final boolean append) { + return writeFileFromIS(getFileByPath(filePath), is, append); + } + + /** + * 将输入流写入文件 + * + * @param file 文件 + * @param is 输入流 + * @return {@code true}: 写入成功
{@code false}: 写入失败 + */ + public static boolean writeFileFromIS(final File file, final InputStream is) { + return writeFileFromIS(file, is, false); + } + + /** + * 将输入流写入文件 + * + * @param file 文件 + * @param is 输入流 + * @param append 是否追加在文件末 + * @return {@code true}: 写入成功
{@code false}: 写入失败 + */ + public static boolean writeFileFromIS(final File file, final InputStream is, final boolean append) { + if (!createOrExistsFile(file) || is == null) return false; + OutputStream os = null; + try { + os = new BufferedOutputStream(new FileOutputStream(file, append)); + byte data[] = new byte[sBufferSize]; + int len; + while ((len = is.read(data, 0, sBufferSize)) != -1) { + os.write(data, 0, len); + } + return true; + } catch (IOException e) { + e.printStackTrace(); + return false; + } finally { + CloseUtils.closeIO(is, os); + } + } + + /** + * 将字节数组写入文件 + * + * @param filePath 文件路径 + * @param bytes 字节数组 + * @return {@code true}: 写入成功
{@code false}: 写入失败 + */ + public static boolean writeFileFromBytesByStream(final String filePath, final byte[] bytes) { + return writeFileFromBytesByStream(getFileByPath(filePath), bytes, false); + } + + /** + * 将字节数组写入文件 + * + * @param filePath 文件路径 + * @param bytes 字节数组 + * @param append 是否追加在文件末 + * @return {@code true}: 写入成功
{@code false}: 写入失败 + */ + public static boolean writeFileFromBytesByStream(final String filePath, final byte[] bytes, final boolean append) { + return writeFileFromBytesByStream(getFileByPath(filePath), bytes, append); + } + + /** + * 将字节数组写入文件 + * + * @param file 文件 + * @param bytes 字节数组 + * @return {@code true}: 写入成功
{@code false}: 写入失败 + */ + public static boolean writeFileFromBytesByStream(final File file, final byte[] bytes) { + return writeFileFromBytesByStream(file, bytes, false); + } + + /** + * 将字节数组写入文件 + * + * @param file 文件 + * @param bytes 字节数组 + * @param append 是否追加在文件末 + * @return {@code true}: 写入成功
{@code false}: 写入失败 + */ + public static boolean writeFileFromBytesByStream(final File file, final byte[] bytes, final boolean append) { + if (bytes == null || !createOrExistsFile(file)) return false; + BufferedOutputStream bos = null; + try { + bos = new BufferedOutputStream(new FileOutputStream(file, append)); + bos.write(bytes); + return true; + } catch (IOException e) { + e.printStackTrace(); + return false; + } finally { + CloseUtils.closeIO(bos); + } + } + + /** + * 将字节数组写入文件 + * + * @param filePath 文件路径 + * @param bytes 字节数组 + * @param isForce 是否写入文件 + * @return {@code true}: 写入成功
{@code false}: 写入失败 + */ + public static boolean writeFileFromBytesByChannel(final String filePath, final byte[] bytes, final boolean isForce) { + return writeFileFromBytesByChannel(getFileByPath(filePath), bytes, false, isForce); + } + + /** + * 将字节数组写入文件 + * + * @param filePath 文件路径 + * @param bytes 字节数组 + * @param append 是否追加在文件末 + * @param isForce 是否写入文件 + * @return {@code true}: 写入成功
{@code false}: 写入失败 + */ + public static boolean writeFileFromBytesByChannel(final String filePath, final byte[] bytes, final boolean append, final boolean isForce) { + return writeFileFromBytesByChannel(getFileByPath(filePath), bytes, append, isForce); + } + + /** + * 将字节数组写入文件 + * + * @param file 文件 + * @param bytes 字节数组 + * @param isForce 是否写入文件 + * @return {@code true}: 写入成功
{@code false}: 写入失败 + */ + public static boolean writeFileFromBytesByChannel(final File file, final byte[] bytes, final boolean isForce) { + return writeFileFromBytesByChannel(file, bytes, false, isForce); + } + + /** + * 将字节数组写入文件 + * + * @param file 文件 + * @param bytes 字节数组 + * @param append 是否追加在文件末 + * @param isForce 是否写入文件 + * @return {@code true}: 写入成功
{@code false}: 写入失败 + */ + public static boolean writeFileFromBytesByChannel(final File file, final byte[] bytes, final boolean append, final boolean isForce) { + if (bytes == null) return false; + FileChannel fc = null; + try { + fc = new FileOutputStream(file, append).getChannel(); + fc.position(fc.size()); + fc.write(ByteBuffer.wrap(bytes)); + if (isForce) fc.force(true); + return true; + } catch (IOException e) { + e.printStackTrace(); + return false; + } finally { + CloseUtils.closeIO(fc); + } + } + + /** + * 将字节数组写入文件 + * + * @param filePath 文件路径 + * @param bytes 字节数组 + * @param isForce 是否写入文件 + * @return {@code true}: 写入成功
{@code false}: 写入失败 + */ + public static boolean writeFileFromBytesByMap(final String filePath, final byte[] bytes, final boolean isForce) { + return writeFileFromBytesByMap(filePath, bytes, false, isForce); + } + + /** + * 将字节数组写入文件 + * + * @param filePath 文件路径 + * @param bytes 字节数组 + * @param append 是否追加在文件末 + * @param isForce 是否写入文件 + * @return {@code true}: 写入成功
{@code false}: 写入失败 + */ + public static boolean writeFileFromBytesByMap(final String filePath, final byte[] bytes, final boolean append, final boolean isForce) { + return writeFileFromBytesByMap(getFileByPath(filePath), bytes, append, isForce); + } + + /** + * 将字节数组写入文件 + * + * @param file 文件 + * @param bytes 字节数组 + * @param isForce 是否写入文件 + * @return {@code true}: 写入成功
{@code false}: 写入失败 + */ + public static boolean writeFileFromBytesByMap(final File file, final byte[] bytes, final boolean isForce) { + return writeFileFromBytesByMap(file, bytes, false, isForce); + } + + /** + * 将字节数组写入文件 + * + * @param file 文件 + * @param bytes 字节数组 + * @param append 是否追加在文件末 + * @param isForce 是否写入文件 + * @return {@code true}: 写入成功
{@code false}: 写入失败 + */ + public static boolean writeFileFromBytesByMap(final File file, final byte[] bytes, final boolean append, final boolean isForce) { + if (bytes == null || !createOrExistsFile(file)) return false; + FileChannel fc = null; + try { + fc = new FileOutputStream(file, append).getChannel(); + MappedByteBuffer mbb = fc.map(FileChannel.MapMode.READ_WRITE, fc.size(), bytes.length); + mbb.put(bytes); + if (isForce) mbb.force(); + return true; + } catch (IOException e) { + e.printStackTrace(); + return false; + } finally { + CloseUtils.closeIO(fc); + } + } + + /** + * 将字符串写入文件 + * + * @param filePath 文件路径 + * @param content 写入内容 + * @return {@code true}: 写入成功
{@code false}: 写入失败 + */ + public static boolean writeFileFromString(final String filePath, final String content) { + return writeFileFromString(getFileByPath(filePath), content, false); + } + + /** + * 将字符串写入文件 + * + * @param filePath 文件路径 + * @param content 写入内容 + * @param append 是否追加在文件末 + * @return {@code true}: 写入成功
{@code false}: 写入失败 + */ + public static boolean writeFileFromString(final String filePath, final String content, final boolean append) { + return writeFileFromString(getFileByPath(filePath), content, append); + } + + /** + * 将字符串写入文件 + * + * @param file 文件 + * @param content 写入内容 + * @return {@code true}: 写入成功
{@code false}: 写入失败 + */ + public static boolean writeFileFromString(final File file, final String content) { + return writeFileFromString(file, content, false); + } + + /** + * 将字符串写入文件 + * + * @param file 文件 + * @param content 写入内容 + * @param append 是否追加在文件末 + * @return {@code true}: 写入成功
{@code false}: 写入失败 + */ + public static boolean writeFileFromString(final File file, final String content, final boolean append) { + if (file == null || content == null) return false; + if (!createOrExistsFile(file)) return false; + BufferedWriter bw = null; + try { + bw = new BufferedWriter(new FileWriter(file, append)); + bw.write(content); + return true; + } catch (IOException e) { + e.printStackTrace(); + return false; + } finally { + CloseUtils.closeIO(bw); + } + } + + /////////////////////////////////////////////////////////////////////////// + // the divide line of write and read + /////////////////////////////////////////////////////////////////////////// + + /** + * 读取文件到字符串链表中 + * + * @param filePath 文件路径 + * @return 字符串链表中 + */ + public static List readFile2List(final String filePath) { + return readFile2List(getFileByPath(filePath), null); + } + + /** + * 读取文件到字符串链表中 + * + * @param filePath 文件路径 + * @param charsetName 编码格式 + * @return 字符串链表中 + */ + public static List readFile2List(final String filePath, final String charsetName) { + return readFile2List(getFileByPath(filePath), charsetName); + } + + /** + * 读取文件到字符串链表中 + * + * @param file 文件 + * @return 字符串链表中 + */ + public static List readFile2List(final File file) { + return readFile2List(file, 0, 0x7FFFFFFF, null); + } + + /** + * 读取文件到字符串链表中 + * + * @param file 文件 + * @param charsetName 编码格式 + * @return 字符串链表中 + */ + public static List readFile2List(final File file, final String charsetName) { + return readFile2List(file, 0, 0x7FFFFFFF, charsetName); + } + + /** + * 读取文件到字符串链表中 + * + * @param filePath 文件路径 + * @param st 需要读取的开始行数 + * @param end 需要读取的结束行数 + * @return 字符串链表中 + */ + public static List readFile2List(final String filePath, final int st, final int end) { + return readFile2List(getFileByPath(filePath), st, end, null); + } + + /** + * 读取文件到字符串链表中 + * + * @param filePath 文件路径 + * @param st 需要读取的开始行数 + * @param end 需要读取的结束行数 + * @param charsetName 编码格式 + * @return 字符串链表中 + */ + public static List readFile2List(final String filePath, final int st, final int end, final String charsetName) { + return readFile2List(getFileByPath(filePath), st, end, charsetName); + } + + /** + * 读取文件到字符串链表中 + * + * @param file 文件 + * @param st 需要读取的开始行数 + * @param end 需要读取的结束行数 + * @return 字符串链表中 + */ + public static List readFile2List(final File file, final int st, final int end) { + return readFile2List(file, st, end, null); + } + + /** + * 读取文件到字符串链表中 + * + * @param file 文件 + * @param st 需要读取的开始行数 + * @param end 需要读取的结束行数 + * @param charsetName 编码格式 + * @return 字符串链表中 + */ + public static List readFile2List(final File file, final int st, final int end, final String charsetName) { + if (!isFileExists(file)) return null; + if (st > end) return null; + BufferedReader reader = null; + try { + String line; + int curLine = 1; + List list = new ArrayList<>(); + if (isSpace(charsetName)) { + reader = new BufferedReader(new InputStreamReader(new FileInputStream(file))); + } else { + reader = new BufferedReader(new InputStreamReader(new FileInputStream(file), charsetName)); + } + while ((line = reader.readLine()) != null) { + if (curLine > end) break; + if (st <= curLine && curLine <= end) list.add(line); + ++curLine; + } + return list; + } catch (IOException e) { + e.printStackTrace(); + return null; + } finally { + CloseUtils.closeIO(reader); + } + } + + /** + * 读取文件到字符串中 + * + * @param filePath 文件路径 + * @return 字符串 + */ + public static String readFile2String(final String filePath) { + return readFile2String(getFileByPath(filePath), null); + } + + /** + * 读取文件到字符串中 + * + * @param filePath 文件路径 + * @param charsetName 编码格式 + * @return 字符串 + */ + public static String readFile2String(final String filePath, final String charsetName) { + return readFile2String(getFileByPath(filePath), charsetName); + } + + /** + * 读取文件到字符串中 + * + * @param file 文件 + * @return 字符串 + */ + public static String readFile2String(final File file) { + return readFile2String(file, null); + } + + /** + * 读取文件到字符串中 + * + * @param file 文件 + * @param charsetName 编码格式 + * @return 字符串 + */ + public static String readFile2String(final File file, final String charsetName) { + if (!isFileExists(file)) return null; + BufferedReader reader = null; + try { + StringBuilder sb = new StringBuilder(); + if (isSpace(charsetName)) { + reader = new BufferedReader(new InputStreamReader(new FileInputStream(file))); + } else { + reader = new BufferedReader(new InputStreamReader(new FileInputStream(file), charsetName)); + } + String line; + if ((line = reader.readLine()) != null) { + sb.append(line); + while ((line = reader.readLine()) != null) { + sb.append(LINE_SEP).append(line); + } + } + return sb.toString(); + } catch (IOException e) { + e.printStackTrace(); + return null; + } finally { + CloseUtils.closeIO(reader); + } + } + + /** + * 读取文件到字节数组中 + * + * @param filePath 文件路径 + * @return 字符数组 + */ + public static byte[] readFile2BytesByStream(final String filePath) { + return readFile2BytesByStream(getFileByPath(filePath)); + } + + /** + * 读取文件到字节数组中 + * + * @param file 文件 + * @return 字符数组 + */ + public static byte[] readFile2BytesByStream(final File file) { + if (!isFileExists(file)) return null; + FileInputStream fis = null; + ByteArrayOutputStream os = null; + try { + fis = new FileInputStream(file); + os = new ByteArrayOutputStream(); + byte[] b = new byte[sBufferSize]; + int len; + while ((len = fis.read(b, 0, sBufferSize)) != -1) { + os.write(b, 0, len); + } + return os.toByteArray(); + } catch (IOException e) { + e.printStackTrace(); + return null; + } finally { + CloseUtils.closeIO(fis, os); + } + } + + /** + * 读取文件到字节数组中 + * + * @param filePath 文件路径 + * @return 字符数组 + */ + public static byte[] readFile2BytesByChannel(final String filePath) { + return readFile2BytesByChannel(getFileByPath(filePath)); + } + + /** + * 读取文件到字节数组中 + * + * @param file 文件 + * @return 字符数组 + */ + public static byte[] readFile2BytesByChannel(final File file) { + if (!isFileExists(file)) return null; + FileChannel fc = null; + try { + fc = new RandomAccessFile(file, "r").getChannel(); + ByteBuffer byteBuffer = ByteBuffer.allocate((int) fc.size()); + while (true) { + if (!((fc.read(byteBuffer)) > 0)) break; + } + return byteBuffer.array(); + } catch (IOException e) { + e.printStackTrace(); + return null; + } finally { + CloseUtils.closeIO(fc); + } + } + + /** + * 读取文件到字节数组中 + * + * @param filePath 文件路径 + * @return 字符数组 + */ + public static byte[] readFile2BytesByMap(final String filePath) { + return readFile2BytesByMap(getFileByPath(filePath)); + } + + /** + * 读取文件到字节数组中 + * + * @param file 文件 + * @return 字符数组 + */ + public static byte[] readFile2BytesByMap(final File file) { + if (!isFileExists(file)) return null; + FileChannel fc = null; + try { + fc = new RandomAccessFile(file, "r").getChannel(); + int size = (int) fc.size(); + MappedByteBuffer mbb = fc.map(FileChannel.MapMode.READ_ONLY, 0, size).load(); + byte[] result = new byte[size]; + mbb.get(result, 0, size); + return result; + } catch (IOException e) { + e.printStackTrace(); + return null; + } finally { + CloseUtils.closeIO(fc); + } + } + + /** + * 读取文件指定位置开始的字节数 + * + * @param file + * @param readSize + * @param offset + * @return + */ + public static byte[] readFile2Byte(final File file, int readSize, long offset) { + + if (!isFileExists(file)) return null; + FileChannel fc = null; + try { + fc = new RandomAccessFile(file, "r").getChannel(); + int size = (int) fc.size(); + if (offset + readSize > size) return null; + + MappedByteBuffer mbb = fc.map(FileChannel.MapMode.READ_ONLY, offset, readSize).load(); + byte[] result = new byte[readSize]; + mbb.get(result, 0, readSize); + return result; + } catch (IOException e) { + e.printStackTrace(); + return null; + } finally { + CloseUtils.closeIO(fc); + } + } + + /** + * 设置缓冲区尺寸 + * + * @param bufferSize 缓冲区大小 + */ + public static void setBufferSize(final int bufferSize) { + sBufferSize = bufferSize; + } + + private static File getFileByPath(final String filePath) { + return isSpace(filePath) ? null : new File(filePath); + } + + private static boolean createOrExistsFile(final String filePath) { + return createOrExistsFile(getFileByPath(filePath)); + } + + private static boolean createOrExistsFile(final File file) { + if (file == null) return false; + if (file.exists()) return file.isFile(); + if (!createOrExistsDir(file.getParentFile())) return false; + try { + return file.createNewFile(); + } catch (IOException e) { + e.printStackTrace(); + return false; + } + } + + private static boolean createOrExistsDir(final File file) { + return file != null && (file.exists() ? file.isDirectory() : file.mkdirs()); + } + + private static boolean isFileExists(final File file) { + return file != null && file.exists(); + } + + private static boolean isSpace(final String s) { + if (s == null) return true; + for (int i = 0, len = s.length(); i < len; ++i) { + if (!Character.isWhitespace(s.charAt(i))) { + return false; + } + } + return true; + } +} diff --git a/app/src/main/java/cn/org/landcloud/survey/util/TimeConstants.java b/app/src/main/java/cn/org/landcloud/survey/util/TimeConstants.java new file mode 100644 index 0000000..7fdfaf0 --- /dev/null +++ b/app/src/main/java/cn/org/landcloud/survey/util/TimeConstants.java @@ -0,0 +1,43 @@ +package cn.org.landcloud.survey.util; + +import androidx.annotation.IntDef; + +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; + +/** + *
+ *     author: Blankj
+ *     blog  : http://blankj.com
+ *     time  : 2017/03/13
+ *     desc  : 时间相关常量
+ * 
+ */ +public final class TimeConstants { + + /** + * 毫秒与毫秒的倍数 + */ + public static final int MSEC = 1; + /** + * 秒与毫秒的倍数 + */ + public static final int SEC = 1000; + /** + * 分与毫秒的倍数 + */ + public static final int MIN = 60000; + /** + * 时与毫秒的倍数 + */ + public static final int HOUR = 3600000; + /** + * 天与毫秒的倍数 + */ + public static final int DAY = 86400000; + + @IntDef({MSEC, SEC, MIN, HOUR, DAY}) + @Retention(RetentionPolicy.SOURCE) + public @interface Unit { + } +} diff --git a/app/src/main/java/cn/org/landcloud/survey/util/TimeUtils.java b/app/src/main/java/cn/org/landcloud/survey/util/TimeUtils.java new file mode 100644 index 0000000..64bdaba --- /dev/null +++ b/app/src/main/java/cn/org/landcloud/survey/util/TimeUtils.java @@ -0,0 +1,1650 @@ +package cn.org.landcloud.survey.util; + + +import android.annotation.SuppressLint; + +import java.text.DateFormat; +import java.text.ParseException; +import java.text.SimpleDateFormat; +import java.util.Calendar; +import java.util.Date; +import java.util.Locale; + +/** + *
+ *     author: Blankj
+ *     blog  : http://blankj.com
+ *     time  : 2016/08/02
+ *     desc  : 时间相关工具类
+ * 
+ */ +public final class TimeUtils { + + /** + *

在工具类中经常使用到工具类的格式化描述,这个主要是一个日期的操作类,所以日志格式主要使用 SimpleDateFormat的定义格式.

+ * 格式的意义如下: 日期和时间模式
+ *

日期和时间格式由日期和时间模式字符串指定。在日期和时间模式字符串中,未加引号的字yy-MM-dd HH:mm母 'A' 到 'Z' 和 'a' 到 'z' + * 被解释为模式字母,用来表示日期或时间字符串元素。文本可以使用单引号 (') 引起来,以免进行解释。"''" + * 表示单引号。所有其他字符均不解释;只是在格式化时将它们简单复制到输出字符串,或者在分析时与输入字符串进行匹配。 + *

+ * 定义了以下模式字母(所有其他字符 'A' 到 'Z' 和 'a' 到 'z' 都被保留):
+ * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + *
字母日期或时间元素表示示例
GEra 标志符TextAD
y Year 1996; 96
M 年中的月份 Month July; Jul; 07
w 年中的周数 Number 27
W 月份中的周数 Number 2
D 年中的天数 Number 189
d 月份中的天数 Number 10
F 月份中的星期 Number 2
E 星期中的天数 Text Tuesday; Tue
a Am/pm 标记 Text PM
H 一天中的小时数(0-23) Number 0
k 一天中的小时数(1-24) Number 24
K am/pm 中的小时数(0-11) Number 0
h am/pm 中的小时数(1-12) Number 12
m 小时中的分钟数 Number 30
s 分钟中的秒数 Number 55
S 毫秒数 Number 978
z 时区 General time zone Pacific Standard Time; PST; GMT-08:00
Z 时区 RFC 822 time zone -0800
+ *
+     *                                             HH:mm    15:44
+     *                                            h:mm a    3:44 下午
+     *                                           HH:mm z    15:44 CST
+     *                                           HH:mm Z    15:44 +0800
+     *                                        HH:mm zzzz    15:44 中国标准时间
+     *                                          HH:mm:ss    15:44:40
+     *                                        yyyy-MM-dd    2016-08-12
+     *                                  yyyy-MM-dd HH:mm    2016-08-12 15:44
+     *                               yyyy-MM-dd HH:mm:ss    2016-08-12 15:44:40
+     *                          yyyy-MM-dd HH:mm:ss zzzz    2016-08-12 15:44:40 中国标准时间
+     *                     EEEE yyyy-MM-dd HH:mm:ss zzzz    星期五 2016-08-12 15:44:40 中国标准时间
+     *                          yyyy-MM-dd HH:mm:ss.SSSZ    2016-08-12 15:44:40.461+0800
+     *                        yyyy-MM-dd'T'HH:mm:ss.SSSZ    2016-08-12T15:44:40.461+0800
+     *                      yyyy.MM.dd G 'at' HH:mm:ss z    2016.08.12 公元 at 15:44:40 CST
+     *                                            K:mm a    3:44 下午
+     *                                  EEE, MMM d, ''yy    星期五, 八月 12, '16
+     *                             hh 'o''clock' a, zzzz    03 o'clock 下午, 中国标准时间
+     *                      yyyyy.MMMMM.dd GGG hh:mm aaa    02016.八月.12 公元 03:44 下午
+     *                        EEE, d MMM yyyy HH:mm:ss Z    星期五, 12 八月 2016 15:44:40 +0800
+     *                                     yyMMddHHmmssZ    160812154440+0800
+     *                        yyyy-MM-dd'T'HH:mm:ss.SSSZ    2016-08-12T15:44:40.461+0800
+     * EEEE 'DATE('yyyy-MM-dd')' 'TIME('HH:mm:ss')' zzzz    星期五 DATE(2016-08-12) TIME(15:44:40) 中国标准时间
+     * 
+ * 注意:SimpleDateFormat不是线程安全的,线程安全需用{@code ThreadLocal} + */ + + private static final DateFormat DEFAULT_FORMAT = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss", Locale.getDefault()); + + private TimeUtils() { + throw new UnsupportedOperationException("u can't instantiate me..."); + } + + /** + * 将时间戳转为时间字符串 + *

格式为yyyy-MM-dd HH:mm:ss

+ * + * @param millis 毫秒时间戳 + * @return 时间字符串 + */ + public static String millis2String(final long millis) { + return millis2String(millis, DEFAULT_FORMAT); + } + + /** + * 将时间戳转为时间字符串 + *

格式为format

+ * + * @param millis 毫秒时间戳 + * @param format 时间格式 + * @return 时间字符串 + */ + public static String millis2String(final long millis, final DateFormat format) { + return format.format(new Date(millis)); + } + + /** + * 将时间字符串转为时间戳 + *

time格式为yyyy-MM-dd HH:mm:ss

+ * + * @param time 时间字符串 + * @return 毫秒时间戳 + */ + public static long string2Millis(final String time) { + return string2Millis(time, DEFAULT_FORMAT); + } + + /** + * 将时间字符串转为时间戳 + *

time格式为format

+ * + * @param time 时间字符串 + * @param format 时间格式 + * @return 毫秒时间戳 + */ + public static long string2Millis(final String time, final DateFormat format) { + try { + return format.parse(time).getTime(); + } catch (ParseException e) { + e.printStackTrace(); + } + return -1; + } + + /** + * 将时间字符串转为Date类型 + *

time格式为yyyy-MM-dd HH:mm:ss

+ * + * @param time 时间字符串 + * @return Date类型 + */ + public static Date string2Date(final String time) { + return string2Date(time, DEFAULT_FORMAT); + } + + /** + * 将时间字符串转为Date类型 + *

time格式为format

+ * + * @param time 时间字符串 + * @param format 时间格式 + * @return Date类型 + */ + public static Date string2Date(final String time, final DateFormat format) { + try { + return format.parse(time); + } catch (ParseException e) { + e.printStackTrace(); + } + return null; + } + + /** + * 将Date类型转为时间字符串 + *

格式为yyyy-MM-dd HH:mm:ss

+ * + * @param date Date类型时间 + * @return 时间字符串 + */ + public static String date2String(final Date date) { + return date2String(date, DEFAULT_FORMAT); + } + + /** + * 将Date类型转为时间字符串 + *

格式为format

+ * + * @param date Date类型时间 + * @param format 时间格式 + * @return 时间字符串 + */ + public static String date2String(final Date date, final DateFormat format) { + return format.format(date); + } + + /** + * 将Date类型转为时间戳 + * + * @param date Date类型时间 + * @return 毫秒时间戳 + */ + public static long date2Millis(final Date date) { + return date.getTime(); + } + + /** + * 将时间戳转为Date类型 + * + * @param millis 毫秒时间戳 + * @return Date类型时间 + */ + public static Date millis2Date(final long millis) { + return new Date(millis); + } + + /** + * 获取两个时间差(单位:unit) + *

time0和time1格式都为yyyy-MM-dd HH:mm:ss

+ * + * @param time0 时间字符串0 + * @param time1 时间字符串1 + * @param unit 单位类型 + *
    + *
  • {@link TimeConstants#MSEC}: 毫秒
  • + *
  • {@link TimeConstants#SEC }: 秒
  • + *
  • {@link TimeConstants#MIN }: 分
  • + *
  • {@link TimeConstants#HOUR}: 小时
  • + *
  • {@link TimeConstants#DAY }: 天
  • + *
+ * @return unit时间戳 + */ + public static long getTimeSpan(final String time0, final String time1, @TimeConstants.Unit final int unit) { + return getTimeSpan(time0, time1, DEFAULT_FORMAT, unit); + } + + /** + * 获取两个时间差(单位:unit) + *

time0和time1格式都为format

+ * + * @param time0 时间字符串0 + * @param time1 时间字符串1 + * @param format 时间格式 + * @param unit 单位类型 + *
    + *
  • {@link TimeConstants#MSEC}: 毫秒
  • + *
  • {@link TimeConstants#SEC }: 秒
  • + *
  • {@link TimeConstants#MIN }: 分
  • + *
  • {@link TimeConstants#HOUR}: 小时
  • + *
  • {@link TimeConstants#DAY }: 天
  • + *
+ * @return unit时间戳 + */ + public static long getTimeSpan(final String time0, final String time1, final DateFormat format, @TimeConstants.Unit final int unit) { + return millis2TimeSpan(Math.abs(string2Millis(time0, format) - string2Millis(time1, format)), unit); + } + + /** + * 获取两个时间差(单位:unit) + * + * @param date0 Date类型时间0 + * @param date1 Date类型时间1 + * @param unit 单位类型 + *
    + *
  • {@link TimeConstants#MSEC}: 毫秒
  • + *
  • {@link TimeConstants#SEC }: 秒
  • + *
  • {@link TimeConstants#MIN }: 分
  • + *
  • {@link TimeConstants#HOUR}: 小时
  • + *
  • {@link TimeConstants#DAY }: 天
  • + *
+ * @return unit时间戳 + */ + public static long getTimeSpan(final Date date0, final Date date1, @TimeConstants.Unit final int unit) { + return millis2TimeSpan(Math.abs(date2Millis(date0) - date2Millis(date1)), unit); + } + + /** + * 获取两个时间差(单位:unit) + * + * @param millis0 毫秒时间戳0 + * @param millis1 毫秒时间戳1 + * @param unit 单位类型 + *
    + *
  • {@link TimeConstants#MSEC}: 毫秒
  • + *
  • {@link TimeConstants#SEC }: 秒
  • + *
  • {@link TimeConstants#MIN }: 分
  • + *
  • {@link TimeConstants#HOUR}: 小时
  • + *
  • {@link TimeConstants#DAY }: 天
  • + *
+ * @return unit时间戳 + */ + public static long getTimeSpan(final long millis0, final long millis1, @TimeConstants.Unit final int unit) { + return millis2TimeSpan(Math.abs(millis0 - millis1), unit); + } + + /** + * 获取合适型两个时间差 + *

time0和time1格式都为yyyy-MM-dd HH:mm:ss

+ * + * @param time0 时间字符串0 + * @param time1 时间字符串1 + * @param precision 精度 + *

precision = 0,返回null

+ *

precision = 1,返回天

+ *

precision = 2,返回天和小时

+ *

precision = 3,返回天、小时和分钟

+ *

precision = 4,返回天、小时、分钟和秒

+ *

precision >= 5,返回天、小时、分钟、秒和毫秒

+ * @return 合适型两个时间差 + */ + public static String getFitTimeSpan(final String time0, final String time1, final int precision) { + return millis2FitTimeSpan(Math.abs(string2Millis(time0, DEFAULT_FORMAT) - string2Millis(time1, DEFAULT_FORMAT)), precision); + } + + /** + * 获取合适型两个时间差 + *

time0和time1格式都为format

+ * + * @param time0 时间字符串0 + * @param time1 时间字符串1 + * @param format 时间格式 + * @param precision 精度 + *

precision = 0,返回null

+ *

precision = 1,返回天

+ *

precision = 2,返回天和小时

+ *

precision = 3,返回天、小时和分钟

+ *

precision = 4,返回天、小时、分钟和秒

+ *

precision >= 5,返回天、小时、分钟、秒和毫秒

+ * @return 合适型两个时间差 + */ + public static String getFitTimeSpan(final String time0, final String time1, final DateFormat format, final int precision) { + return millis2FitTimeSpan(Math.abs(string2Millis(time0, format) - string2Millis(time1, format)), precision); + } + + /** + * 获取合适型两个时间差 + * + * @param date0 Date类型时间0 + * @param date1 Date类型时间1 + * @param precision 精度 + *

precision = 0,返回null

+ *

precision = 1,返回天

+ *

precision = 2,返回天和小时

+ *

precision = 3,返回天、小时和分钟

+ *

precision = 4,返回天、小时、分钟和秒

+ *

precision >= 5,返回天、小时、分钟、秒和毫秒

+ * @return 合适型两个时间差 + */ + public static String getFitTimeSpan(final Date date0, final Date date1, final int precision) { + return millis2FitTimeSpan(Math.abs(date2Millis(date0) - date2Millis(date1)), precision); + } + + /** + * 获取合适型两个时间差 + * + * @param millis0 毫秒时间戳1 + * @param millis1 毫秒时间戳2 + * @param precision 精度 + *

precision = 0,返回null

+ *

precision = 1,返回天

+ *

precision = 2,返回天和小时

+ *

precision = 3,返回天、小时和分钟

+ *

precision = 4,返回天、小时、分钟和秒

+ *

precision >= 5,返回天、小时、分钟、秒和毫秒

+ * @return 合适型两个时间差 + */ + public static String getFitTimeSpan(final long millis0, final long millis1, final int precision) { + return millis2FitTimeSpan(Math.abs(millis0 - millis1), precision); + } + + /** + * 获取当前毫秒时间戳 + * + * @return 毫秒时间戳 + */ + public static long getNowMills() { + return System.currentTimeMillis(); + } + + /** + * 获取当前时间字符串 + *

格式为yyyy-MM-dd HH:mm:ss

+ * + * @return 时间字符串 + */ + public static String getNowString() { + return millis2String(System.currentTimeMillis(), DEFAULT_FORMAT); + } + + /** + * 获取当前时间字符串 + *

格式为format

+ * + * @param format 时间格式 + * @return 时间字符串 + */ + public static String getNowString(final DateFormat format) { + return millis2String(System.currentTimeMillis(), format); + } + + /** + * 获取当前Date + * + * @return Date类型时间 + */ + public static Date getNowDate() { + return new Date(); + } + + /** + * 获取与当前时间的差(单位:unit) + *

time格式为yyyy-MM-dd HH:mm:ss

+ * + * @param time 时间字符串 + * @param unit 单位类型 + *
    + *
  • {@link TimeConstants#MSEC}: 毫秒
  • + *
  • {@link TimeConstants#SEC }: 秒
  • + *
  • {@link TimeConstants#MIN }: 分
  • + *
  • {@link TimeConstants#HOUR}: 小时
  • + *
  • {@link TimeConstants#DAY }: 天
  • + *
+ * @return unit时间戳 + */ + public static long getTimeSpanByNow(final String time, @TimeConstants.Unit final int unit) { + return getTimeSpan(getNowString(), time, DEFAULT_FORMAT, unit); + } + + /** + * 获取与当前时间的差(单位:unit) + *

time格式为format

+ * + * @param time 时间字符串 + * @param format 时间格式 + * @param unit 单位类型 + *
    + *
  • {@link TimeConstants#MSEC}: 毫秒
  • + *
  • {@link TimeConstants#SEC }: 秒
  • + *
  • {@link TimeConstants#MIN }: 分
  • + *
  • {@link TimeConstants#HOUR}: 小时
  • + *
  • {@link TimeConstants#DAY }: 天
  • + *
+ * @return unit时间戳 + */ + public static long getTimeSpanByNow(final String time, final DateFormat format, @TimeConstants.Unit final int unit) { + return getTimeSpan(getNowString(format), time, format, unit); + } + + /** + * 获取与当前时间的差(单位:unit) + * + * @param date Date类型时间 + * @param unit 单位类型 + *
    + *
  • {@link TimeConstants#MSEC}: 毫秒
  • + *
  • {@link TimeConstants#SEC }: 秒
  • + *
  • {@link TimeConstants#MIN }: 分
  • + *
  • {@link TimeConstants#HOUR}: 小时
  • + *
  • {@link TimeConstants#DAY }: 天
  • + *
+ * @return unit时间戳 + */ + public static long getTimeSpanByNow(final Date date, @TimeConstants.Unit final int unit) { + return getTimeSpan(new Date(), date, unit); + } + + /** + * 获取与当前时间的差(单位:unit) + * + * @param millis 毫秒时间戳 + * @param unit 单位类型 + *
    + *
  • {@link TimeConstants#MSEC}: 毫秒
  • + *
  • {@link TimeConstants#SEC }: 秒
  • + *
  • {@link TimeConstants#MIN }: 分
  • + *
  • {@link TimeConstants#HOUR}: 小时
  • + *
  • {@link TimeConstants#DAY }: 天
  • + *
+ * @return unit时间戳 + */ + public static long getTimeSpanByNow(final long millis, @TimeConstants.Unit final int unit) { + return getTimeSpan(System.currentTimeMillis(), millis, unit); + } + + /** + * 获取合适型与当前时间的差 + *

time格式为yyyy-MM-dd HH:mm:ss

+ * + * @param time 时间字符串 + * @param precision 精度 + *
    + *
  • precision = 0,返回null
  • + *
  • precision = 1,返回天
  • + *
  • precision = 2,返回天和小时
  • + *
  • precision = 3,返回天、小时和分钟
  • + *
  • precision = 4,返回天、小时、分钟和秒
  • + *
  • precision >= 5,返回天、小时、分钟、秒和毫秒
  • + *
+ * @return 合适型与当前时间的差 + */ + public static String getFitTimeSpanByNow(final String time, final int precision) { + return getFitTimeSpan(getNowString(), time, DEFAULT_FORMAT, precision); + } + + /** + * 获取合适型与当前时间的差 + *

time格式为format

+ * + * @param time 时间字符串 + * @param format 时间格式 + * @param precision 精度 + *
    + *
  • precision = 0,返回null
  • + *
  • precision = 1,返回天
  • + *
  • precision = 2,返回天和小时
  • + *
  • precision = 3,返回天、小时和分钟
  • + *
  • precision = 4,返回天、小时、分钟和秒
  • + *
  • precision >= 5,返回天、小时、分钟、秒和毫秒
  • + *
+ * @return 合适型与当前时间的差 + */ + public static String getFitTimeSpanByNow(final String time, final DateFormat format, final int precision) { + return getFitTimeSpan(getNowString(format), time, format, precision); + } + + /** + * 获取合适型与当前时间的差 + * + * @param date Date类型时间 + * @param precision 精度 + *
    + *
  • precision = 0,返回null
  • + *
  • precision = 1,返回天
  • + *
  • precision = 2,返回天和小时
  • + *
  • precision = 3,返回天、小时和分钟
  • + *
  • precision = 4,返回天、小时、分钟和秒
  • + *
  • precision >= 5,返回天、小时、分钟、秒和毫秒
  • + *
+ * @return 合适型与当前时间的差 + */ + public static String getFitTimeSpanByNow(final Date date, final int precision) { + return getFitTimeSpan(getNowDate(), date, precision); + } + + /** + * 获取合适型与当前时间的差 + * + * @param millis 毫秒时间戳 + * @param precision 精度 + *
    + *
  • precision = 0,返回null
  • + *
  • precision = 1,返回天
  • + *
  • precision = 2,返回天和小时
  • + *
  • precision = 3,返回天、小时和分钟
  • + *
  • precision = 4,返回天、小时、分钟和秒
  • + *
  • precision >= 5,返回天、小时、分钟、秒和毫秒
  • + *
+ * @return 合适型与当前时间的差 + */ + public static String getFitTimeSpanByNow(final long millis, final int precision) { + return getFitTimeSpan(System.currentTimeMillis(), millis, precision); + } + + /** + * 获取友好型与当前时间的差 + *

time格式为yyyy-MM-dd HH:mm:ss

+ * + * @param time 时间字符串 + * @return 友好型与当前时间的差 + *
    + *
  • 如果小于1秒钟内,显示刚刚
  • + *
  • 如果在1分钟内,显示XXX秒前
  • + *
  • 如果在1小时内,显示XXX分钟前
  • + *
  • 如果在1小时外的今天内,显示今天15:32
  • + *
  • 如果是昨天的,显示昨天15:32
  • + *
  • 其余显示,2016-10-15
  • + *
  • 时间不合法的情况全部日期和时间信息,如星期六 十月 27 14:21:20 CST 2007
  • + *
+ */ + public static String getFriendlyTimeSpanByNow(final String time) { + return getFriendlyTimeSpanByNow(time, DEFAULT_FORMAT); + } + + /** + * 获取友好型与当前时间的差 + *

time格式为format

+ * + * @param time 时间字符串 + * @param format 时间格式 + * @return 友好型与当前时间的差 + *
    + *
  • 如果小于1秒钟内,显示刚刚
  • + *
  • 如果在1分钟内,显示XXX秒前
  • + *
  • 如果在1小时内,显示XXX分钟前
  • + *
  • 如果在1小时外的今天内,显示今天15:32
  • + *
  • 如果是昨天的,显示昨天15:32
  • + *
  • 其余显示,2016-10-15
  • + *
  • 时间不合法的情况全部日期和时间信息,如星期六 十月 27 14:21:20 CST 2007
  • + *
+ */ + public static String getFriendlyTimeSpanByNow(final String time, final DateFormat format) { + return getFriendlyTimeSpanByNow(string2Millis(time, format)); + } + + /** + * 获取友好型与当前时间的差 + * + * @param date Date类型时间 + * @return 友好型与当前时间的差 + *
    + *
  • 如果小于1秒钟内,显示刚刚
  • + *
  • 如果在1分钟内,显示XXX秒前
  • + *
  • 如果在1小时内,显示XXX分钟前
  • + *
  • 如果在1小时外的今天内,显示今天15:32
  • + *
  • 如果是昨天的,显示昨天15:32
  • + *
  • 其余显示,2016-10-15
  • + *
  • 时间不合法的情况全部日期和时间信息,如星期六 十月 27 14:21:20 CST 2007
  • + *
+ */ + public static String getFriendlyTimeSpanByNow(final Date date) { + return getFriendlyTimeSpanByNow(date.getTime()); + } + + /** + * 获取友好型与当前时间的差 + * + * @param millis 毫秒时间戳 + * @return 友好型与当前时间的差 + *
    + *
  • 如果小于1秒钟内,显示刚刚
  • + *
  • 如果在1分钟内,显示XXX秒前
  • + *
  • 如果在1小时内,显示XXX分钟前
  • + *
  • 如果在1小时外的今天内,显示今天15:32
  • + *
  • 如果是昨天的,显示昨天15:32
  • + *
  • 其余显示,2016-10-15
  • + *
  • 时间不合法的情况全部日期和时间信息,如星期六 十月 27 14:21:20 CST 2007
  • + *
+ */ + public static String getFriendlyTimeSpanByNow(final long millis) { + long now = System.currentTimeMillis(); + long span = now - millis; + if (span < 0) + return String.format("%tc", millis);// U can read http://www.apihome.cn/api/java/Formatter.html to understand it. + if (span < 1000) { + return "刚刚"; + } else if (span < TimeConstants.MIN) { + return String.format(Locale.getDefault(), "%d秒前", span / TimeConstants.SEC); + } else if (span < TimeConstants.HOUR) { + return String.format(Locale.getDefault(), "%d分钟前", span / TimeConstants.MIN); + } + // 获取当天00:00 + long wee = getWeeOfToday(); + if (millis >= wee) { + return String.format("今天%tR", millis); + } else if (millis >= wee - TimeConstants.DAY) { + return String.format("昨天%tR", millis); + } else { + return String.format("%tF", millis); + } + } + + private static long getWeeOfToday() { + Calendar cal = Calendar.getInstance(); + cal.set(Calendar.HOUR_OF_DAY, 0); + cal.set(Calendar.SECOND, 0); + cal.set(Calendar.MINUTE, 0); + cal.set(Calendar.MILLISECOND, 0); + return cal.getTimeInMillis(); + } + + /** + * 获取与给定时间等于时间差的时间戳 + * + * @param millis 给定时间 + * @param timeSpan 时间差的毫秒时间戳 + * @param unit 单位类型 + *
    + *
  • {@link TimeConstants#MSEC}: 毫秒
  • + *
  • {@link TimeConstants#SEC }: 秒
  • + *
  • {@link TimeConstants#MIN }: 分
  • + *
  • {@link TimeConstants#HOUR}: 小时
  • + *
  • {@link TimeConstants#DAY }: 天
  • + *
+ * @return 与给定时间等于时间差的时间戳 + */ + public static long getMillis(final long millis, final long timeSpan, @TimeConstants.Unit final int unit) { + return millis + timeSpan2Millis(timeSpan, unit); + } + + /** + * 获取与给定时间等于时间差的时间戳 + *

time格式为yyyy-MM-dd HH:mm:ss

+ * + * @param time 给定时间 + * @param timeSpan 时间差的毫秒时间戳 + * @param unit 单位类型 + *
    + *
  • {@link TimeConstants#MSEC}: 毫秒
  • + *
  • {@link TimeConstants#SEC }: 秒
  • + *
  • {@link TimeConstants#MIN }: 分
  • + *
  • {@link TimeConstants#HOUR}: 小时
  • + *
  • {@link TimeConstants#DAY }: 天
  • + *
+ * @return 与给定时间等于时间差的时间戳 + */ + public static long getMillis(final String time, final long timeSpan, @TimeConstants.Unit final int unit) { + return getMillis(time, DEFAULT_FORMAT, timeSpan, unit); + } + + /** + * 获取与给定时间等于时间差的时间戳 + *

time格式为format

+ * + * @param time 给定时间 + * @param format 时间格式 + * @param timeSpan 时间差的毫秒时间戳 + * @param unit 单位类型 + *
    + *
  • {@link TimeConstants#MSEC}: 毫秒
  • + *
  • {@link TimeConstants#SEC }: 秒
  • + *
  • {@link TimeConstants#MIN }: 分
  • + *
  • {@link TimeConstants#HOUR}: 小时
  • + *
  • {@link TimeConstants#DAY }: 天
  • + *
+ * @return 与给定时间等于时间差的时间戳 + */ + public static long getMillis(final String time, final DateFormat format, final long timeSpan, @TimeConstants.Unit final int unit) { + return string2Millis(time, format) + timeSpan2Millis(timeSpan, unit); + } + + /** + * 获取与给定时间等于时间差的时间戳 + * + * @param date 给定时间 + * @param timeSpan 时间差的毫秒时间戳 + * @param unit 单位类型 + *
    + *
  • {@link TimeConstants#MSEC}: 毫秒
  • + *
  • {@link TimeConstants#SEC }: 秒
  • + *
  • {@link TimeConstants#MIN }: 分
  • + *
  • {@link TimeConstants#HOUR}: 小时
  • + *
  • {@link TimeConstants#DAY }: 天
  • + *
+ * @return 与给定时间等于时间差的时间戳 + */ + public static long getMillis(final Date date, final long timeSpan, @TimeConstants.Unit final int unit) { + return date2Millis(date) + timeSpan2Millis(timeSpan, unit); + } + + /** + * 获取与给定时间等于时间差的时间字符串 + *

格式为yyyy-MM-dd HH:mm:ss

+ * + * @param millis 给定时间 + * @param timeSpan 时间差的毫秒时间戳 + * @param unit 单位类型 + *
    + *
  • {@link TimeConstants#MSEC}: 毫秒
  • + *
  • {@link TimeConstants#SEC }: 秒
  • + *
  • {@link TimeConstants#MIN }: 分
  • + *
  • {@link TimeConstants#HOUR}: 小时
  • + *
  • {@link TimeConstants#DAY }: 天
  • + *
+ * @return 与给定时间等于时间差的时间字符串 + */ + public static String getString(final long millis, final long timeSpan, @TimeConstants.Unit final int unit) { + return getString(millis, DEFAULT_FORMAT, timeSpan, unit); + } + + /** + * 获取与给定时间等于时间差的时间字符串 + *

格式为format

+ * + * @param millis 给定时间 + * @param format 时间格式 + * @param timeSpan 时间差的毫秒时间戳 + * @param unit 单位类型 + *
    + *
  • {@link TimeConstants#MSEC}: 毫秒
  • + *
  • {@link TimeConstants#SEC }: 秒
  • + *
  • {@link TimeConstants#MIN }: 分
  • + *
  • {@link TimeConstants#HOUR}: 小时
  • + *
  • {@link TimeConstants#DAY }: 天
  • + *
+ * @return 与给定时间等于时间差的时间字符串 + */ + public static String getString(final long millis, final DateFormat format, final long timeSpan, @TimeConstants.Unit final int unit) { + return millis2String(millis + timeSpan2Millis(timeSpan, unit), format); + } + + /** + * 获取与给定时间等于时间差的时间字符串 + *

time格式为yyyy-MM-dd HH:mm:ss

+ * + * @param time 给定时间 + * @param timeSpan 时间差的毫秒时间戳 + * @param unit 单位类型 + *
    + *
  • {@link TimeConstants#MSEC}: 毫秒
  • + *
  • {@link TimeConstants#SEC }: 秒
  • + *
  • {@link TimeConstants#MIN }: 分
  • + *
  • {@link TimeConstants#HOUR}: 小时
  • + *
  • {@link TimeConstants#DAY }: 天
  • + *
+ * @return 与给定时间等于时间差的时间字符串 + */ + public static String getString(final String time, final long timeSpan, @TimeConstants.Unit final int unit) { + return getString(time, DEFAULT_FORMAT, timeSpan, unit); + } + + /** + * 获取与给定时间等于时间差的时间字符串 + *

格式为format

+ * + * @param time 给定时间 + * @param format 时间格式 + * @param timeSpan 时间差的毫秒时间戳 + * @param unit 单位类型 + *
    + *
  • {@link TimeConstants#MSEC}: 毫秒
  • + *
  • {@link TimeConstants#SEC }: 秒
  • + *
  • {@link TimeConstants#MIN }: 分
  • + *
  • {@link TimeConstants#HOUR}: 小时
  • + *
  • {@link TimeConstants#DAY }: 天
  • + *
+ * @return 与给定时间等于时间差的时间字符串 + */ + public static String getString(final String time, final DateFormat format, final long timeSpan, @TimeConstants.Unit final int unit) { + return millis2String(string2Millis(time, format) + timeSpan2Millis(timeSpan, unit), format); + } + + /** + * 获取与给定时间等于时间差的时间字符串 + *

格式为yyyy-MM-dd HH:mm:ss

+ * + * @param date 给定时间 + * @param timeSpan 时间差的毫秒时间戳 + * @param unit 单位类型 + *
    + *
  • {@link TimeConstants#MSEC}: 毫秒
  • + *
  • {@link TimeConstants#SEC }: 秒
  • + *
  • {@link TimeConstants#MIN }: 分
  • + *
  • {@link TimeConstants#HOUR}: 小时
  • + *
  • {@link TimeConstants#DAY }: 天
  • + *
+ * @return 与给定时间等于时间差的时间字符串 + */ + public static String getString(final Date date, final long timeSpan, @TimeConstants.Unit final int unit) { + return getString(date, DEFAULT_FORMAT, timeSpan, unit); + } + + /** + * 获取与给定时间等于时间差的时间字符串 + *

格式为format

+ * + * @param date 给定时间 + * @param format 时间格式 + * @param timeSpan 时间差的毫秒时间戳 + * @param unit 单位类型 + *
    + *
  • {@link TimeConstants#MSEC}: 毫秒
  • + *
  • {@link TimeConstants#SEC }: 秒
  • + *
  • {@link TimeConstants#MIN }: 分
  • + *
  • {@link TimeConstants#HOUR}: 小时
  • + *
  • {@link TimeConstants#DAY }: 天
  • + *
+ * @return 与给定时间等于时间差的时间字符串 + */ + public static String getString(final Date date, final DateFormat format, final long timeSpan, @TimeConstants.Unit final int unit) { + return millis2String(date2Millis(date) + timeSpan2Millis(timeSpan, unit), format); + } + + /** + * 获取与给定时间等于时间差的Date + * + * @param millis 给定时间 + * @param timeSpan 时间差的毫秒时间戳 + * @param unit 单位类型 + *
    + *
  • {@link TimeConstants#MSEC}: 毫秒
  • + *
  • {@link TimeConstants#SEC }: 秒
  • + *
  • {@link TimeConstants#MIN }: 分
  • + *
  • {@link TimeConstants#HOUR}: 小时
  • + *
  • {@link TimeConstants#DAY }: 天
  • + *
+ * @return 与给定时间等于时间差的Date + */ + public static Date getDate(final long millis, final long timeSpan, @TimeConstants.Unit final int unit) { + return millis2Date(millis + timeSpan2Millis(timeSpan, unit)); + } + + /** + * 获取与给定时间等于时间差的Date + *

time格式为yyyy-MM-dd HH:mm:ss

+ * + * @param time 给定时间 + * @param timeSpan 时间差的毫秒时间戳 + * @param unit 单位类型 + *
    + *
  • {@link TimeConstants#MSEC}: 毫秒
  • + *
  • {@link TimeConstants#SEC }: 秒
  • + *
  • {@link TimeConstants#MIN }: 分
  • + *
  • {@link TimeConstants#HOUR}: 小时
  • + *
  • {@link TimeConstants#DAY }: 天
  • + *
+ * @return 与给定时间等于时间差的Date + */ + public static Date getDate(final String time, final long timeSpan, @TimeConstants.Unit final int unit) { + return getDate(time, DEFAULT_FORMAT, timeSpan, unit); + } + + /** + * 获取与给定时间等于时间差的Date + *

格式为format

+ * + * @param time 给定时间 + * @param format 时间格式 + * @param timeSpan 时间差的毫秒时间戳 + * @param unit 单位类型 + *
    + *
  • {@link TimeConstants#MSEC}: 毫秒
  • + *
  • {@link TimeConstants#SEC }: 秒
  • + *
  • {@link TimeConstants#MIN }: 分
  • + *
  • {@link TimeConstants#HOUR}: 小时
  • + *
  • {@link TimeConstants#DAY }: 天
  • + *
+ * @return 与给定时间等于时间差的Date + */ + public static Date getDate(final String time, final DateFormat format, final long timeSpan, @TimeConstants.Unit final int unit) { + return millis2Date(string2Millis(time, format) + timeSpan2Millis(timeSpan, unit)); + } + + /** + * 获取与给定时间等于时间差的Date + * + * @param date 给定时间 + * @param timeSpan 时间差的毫秒时间戳 + * @param unit 单位类型 + *
    + *
  • {@link TimeConstants#MSEC}: 毫秒
  • + *
  • {@link TimeConstants#SEC }: 秒
  • + *
  • {@link TimeConstants#MIN }: 分
  • + *
  • {@link TimeConstants#HOUR}: 小时
  • + *
  • {@link TimeConstants#DAY }: 天
  • + *
+ * @return 与给定时间等于时间差的Date + */ + public static Date getDate(final Date date, final long timeSpan, @TimeConstants.Unit final int unit) { + return millis2Date(date2Millis(date) + timeSpan2Millis(timeSpan, unit)); + } + + /** + * 获取与当前时间等于时间差的时间戳 + * + * @param timeSpan 时间差的毫秒时间戳 + * @param unit 单位类型 + *
    + *
  • {@link TimeConstants#MSEC}: 毫秒
  • + *
  • {@link TimeConstants#SEC }: 秒
  • + *
  • {@link TimeConstants#MIN }: 分
  • + *
  • {@link TimeConstants#HOUR}: 小时
  • + *
  • {@link TimeConstants#DAY }: 天
  • + *
+ * @return 与当前时间等于时间差的时间戳 + */ + public static long getMillisByNow(final long timeSpan, @TimeConstants.Unit final int unit) { + return getMillis(getNowMills(), timeSpan, unit); + } + + /** + * 获取与当前时间等于时间差的时间字符串 + *

格式为yyyy-MM-dd HH:mm:ss

+ * + * @param timeSpan 时间差的毫秒时间戳 + * @param unit 单位类型 + *
    + *
  • {@link TimeConstants#MSEC}: 毫秒
  • + *
  • {@link TimeConstants#SEC }: 秒
  • + *
  • {@link TimeConstants#MIN }: 分
  • + *
  • {@link TimeConstants#HOUR}: 小时
  • + *
  • {@link TimeConstants#DAY }: 天
  • + *
+ * @return 与当前时间等于时间差的时间字符串 + */ + public static String getStringByNow(final long timeSpan, @TimeConstants.Unit final int unit) { + return getStringByNow(timeSpan, DEFAULT_FORMAT, unit); + } + + /** + * 获取与当前时间等于时间差的时间字符串 + *

格式为format

+ * + * @param timeSpan 时间差的毫秒时间戳 + * @param format 时间格式 + * @param unit 单位类型 + *
    + *
  • {@link TimeConstants#MSEC}: 毫秒
  • + *
  • {@link TimeConstants#SEC }: 秒
  • + *
  • {@link TimeConstants#MIN }: 分
  • + *
  • {@link TimeConstants#HOUR}: 小时
  • + *
  • {@link TimeConstants#DAY }: 天
  • + *
+ * @return 与当前时间等于时间差的时间字符串 + */ + public static String getStringByNow(final long timeSpan, final DateFormat format, @TimeConstants.Unit final int unit) { + return getString(getNowMills(), format, timeSpan, unit); + } + + /** + * 获取与当前时间等于时间差的Date + * + * @param timeSpan 时间差的毫秒时间戳 + * @param unit 单位类型 + *
    + *
  • {@link TimeConstants#MSEC}: 毫秒
  • + *
  • {@link TimeConstants#SEC }: 秒
  • + *
  • {@link TimeConstants#MIN }: 分
  • + *
  • {@link TimeConstants#HOUR}: 小时
  • + *
  • {@link TimeConstants#DAY }: 天
  • + *
+ * @return 与当前时间等于时间差的Date + */ + public static Date getDateByNow(final long timeSpan, @TimeConstants.Unit final int unit) { + return getDate(getNowMills(), timeSpan, unit); + } + + /** + * 判断是否今天 + *

time格式为yyyy-MM-dd HH:mm:ss

+ * + * @param time 时间字符串 + * @return {@code true}: 是
{@code false}: 否 + */ + public static boolean isToday(final String time) { + return isToday(string2Millis(time, DEFAULT_FORMAT)); + } + + /** + * 判断是否今天 + *

time格式为format

+ * + * @param time 时间字符串 + * @param format 时间格式 + * @return {@code true}: 是
{@code false}: 否 + */ + public static boolean isToday(final String time, final DateFormat format) { + return isToday(string2Millis(time, format)); + } + + /** + * 判断是否今天 + * + * @param date Date类型时间 + * @return {@code true}: 是
{@code false}: 否 + */ + public static boolean isToday(final Date date) { + return isToday(date.getTime()); + } + + /** + * 判断是否今天 + * + * @param millis 毫秒时间戳 + * @return {@code true}: 是
{@code false}: 否 + */ + public static boolean isToday(final long millis) { + long wee = getWeeOfToday(); + return millis >= wee && millis < wee + TimeConstants.DAY; + } + + /** + * 判断是否闰年 + *

time格式为yyyy-MM-dd HH:mm:ss

+ * + * @param time 时间字符串 + * @return {@code true}: 闰年
{@code false}: 平年 + */ + public static boolean isLeapYear(final String time) { + return isLeapYear(string2Date(time, DEFAULT_FORMAT)); + } + + /** + * 判断是否闰年 + *

time格式为format

+ * + * @param time 时间字符串 + * @param format 时间格式 + * @return {@code true}: 闰年
{@code false}: 平年 + */ + public static boolean isLeapYear(final String time, final DateFormat format) { + return isLeapYear(string2Date(time, format)); + } + + /** + * 判断是否闰年 + * + * @param date Date类型时间 + * @return {@code true}: 闰年
{@code false}: 平年 + */ + public static boolean isLeapYear(final Date date) { + Calendar cal = Calendar.getInstance(); + cal.setTime(date); + int year = cal.get(Calendar.YEAR); + return isLeapYear(year); + } + + /** + * 判断是否闰年 + * + * @param millis 毫秒时间戳 + * @return {@code true}: 闰年
{@code false}: 平年 + */ + public static boolean isLeapYear(final long millis) { + return isLeapYear(millis2Date(millis)); + } + + /** + * 判断是否闰年 + * + * @param year 年份 + * @return {@code true}: 闰年
{@code false}: 平年 + */ + public static boolean isLeapYear(final int year) { + return year % 4 == 0 && year % 100 != 0 || year % 400 == 0; + } + + /** + * 获取中式星期 + *

time格式为yyyy-MM-dd HH:mm:ss

+ * + * @param time 时间字符串 + * @return 中式星期 + */ + public static String getChineseWeek(final String time) { + return getChineseWeek(string2Date(time, DEFAULT_FORMAT)); + } + + /** + * 获取中式星期 + *

time格式为format

+ * + * @param time 时间字符串 + * @param format 时间格式 + * @return 中式星期 + */ + public static String getChineseWeek(final String time, final DateFormat format) { + return getChineseWeek(string2Date(time, format)); + } + + /** + * 获取中式星期 + * + * @param date Date类型时间 + * @return 中式星期 + */ + public static String getChineseWeek(final Date date) { + return new SimpleDateFormat("E", Locale.CHINA).format(date); + } + + /** + * 获取中式星期 + * + * @param millis 毫秒时间戳 + * @return 中式星期 + */ + public static String getChineseWeek(final long millis) { + return getChineseWeek(new Date(millis)); + } + + /** + * 获取美式星期 + *

time格式为yyyy-MM-dd HH:mm:ss

+ * + * @param time 时间字符串 + * @return 美式星期 + */ + public static String getUSWeek(final String time) { + return getUSWeek(string2Date(time, DEFAULT_FORMAT)); + } + + /** + * 获取美式星期 + *

time格式为format

+ * + * @param time 时间字符串 + * @param format 时间格式 + * @return 美式星期 + */ + public static String getUSWeek(final String time, final DateFormat format) { + return getUSWeek(string2Date(time, format)); + } + + /** + * 获取美式星期 + * + * @param date Date类型时间 + * @return 美式星期 + */ + public static String getUSWeek(final Date date) { + return new SimpleDateFormat("EEEE", Locale.US).format(date); + } + + /** + * 获取美式星期 + * + * @param millis 毫秒时间戳 + * @return 美式星期 + */ + public static String getUSWeek(final long millis) { + return getUSWeek(new Date(millis)); + } + + /** + * 获取星期索引 + *

注意:周日的Index才是1,周六为7

+ *

time格式为yyyy-MM-dd HH:mm:ss

+ * + * @param time 时间字符串 + * @return 1...7 + * @see Calendar#SUNDAY + * @see Calendar#MONDAY + * @see Calendar#TUESDAY + * @see Calendar#WEDNESDAY + * @see Calendar#THURSDAY + * @see Calendar#FRIDAY + * @see Calendar#SATURDAY + */ + public static int getWeekIndex(final String time) { + return getWeekIndex(string2Date(time, DEFAULT_FORMAT)); + } + + /** + * 获取星期索引 + *

注意:周日的Index才是1,周六为7

+ *

time格式为format

+ * + * @param time 时间字符串 + * @param format 时间格式 + * @return 1...7 + * @see Calendar#SUNDAY + * @see Calendar#MONDAY + * @see Calendar#TUESDAY + * @see Calendar#WEDNESDAY + * @see Calendar#THURSDAY + * @see Calendar#FRIDAY + * @see Calendar#SATURDAY + */ + public static int getWeekIndex(final String time, final DateFormat format) { + return getWeekIndex(string2Date(time, format)); + } + + /** + * 获取星期索引 + *

注意:周日的Index才是1,周六为7

+ * + * @param date Date类型时间 + * @return 1...7 + * @see Calendar#SUNDAY + * @see Calendar#MONDAY + * @see Calendar#TUESDAY + * @see Calendar#WEDNESDAY + * @see Calendar#THURSDAY + * @see Calendar#FRIDAY + * @see Calendar#SATURDAY + */ + public static int getWeekIndex(final Date date) { + Calendar cal = Calendar.getInstance(); + cal.setTime(date); + return cal.get(Calendar.DAY_OF_WEEK); + } + + /** + * 获取星期索引 + *

注意:周日的Index才是1,周六为7

+ * + * @param millis 毫秒时间戳 + * @return 1...7 + * @see Calendar#SUNDAY + * @see Calendar#MONDAY + * @see Calendar#TUESDAY + * @see Calendar#WEDNESDAY + * @see Calendar#THURSDAY + * @see Calendar#FRIDAY + * @see Calendar#SATURDAY + */ + public static int getWeekIndex(final long millis) { + return getWeekIndex(millis2Date(millis)); + } + + /** + * 获取月份中的第几周 + *

注意:国外周日才是新的一周的开始

+ *

time格式为yyyy-MM-dd HH:mm:ss

+ * + * @param time 时间字符串 + * @return 1...5 + */ + public static int getWeekOfMonth(final String time) { + return getWeekOfMonth(string2Date(time, DEFAULT_FORMAT)); + } + + /** + * 获取月份中的第几周 + *

注意:国外周日才是新的一周的开始

+ *

time格式为format

+ * + * @param time 时间字符串 + * @param format 时间格式 + * @return 1...5 + */ + public static int getWeekOfMonth(final String time, final DateFormat format) { + return getWeekOfMonth(string2Date(time, format)); + } + + /** + * 获取月份中的第几周 + *

注意:国外周日才是新的一周的开始

+ * + * @param date Date类型时间 + * @return 1...5 + */ + public static int getWeekOfMonth(final Date date) { + Calendar cal = Calendar.getInstance(); + cal.setTime(date); + return cal.get(Calendar.WEEK_OF_MONTH); + } + + /** + * 获取月份中的第几周 + *

注意:国外周日才是新的一周的开始

+ * + * @param millis 毫秒时间戳 + * @return 1...5 + */ + public static int getWeekOfMonth(final long millis) { + return getWeekOfMonth(millis2Date(millis)); + } + + /** + * 获取年份中的第几周 + *

注意:国外周日才是新的一周的开始

+ *

time格式为yyyy-MM-dd HH:mm:ss

+ * + * @param time 时间字符串 + * @return 1...54 + */ + public static int getWeekOfYear(final String time) { + return getWeekOfYear(string2Date(time, DEFAULT_FORMAT)); + } + + /** + * 获取年份中的第几周 + *

注意:国外周日才是新的一周的开始

+ *

time格式为format

+ * + * @param time 时间字符串 + * @param format 时间格式 + * @return 1...54 + */ + public static int getWeekOfYear(final String time, final DateFormat format) { + return getWeekOfYear(string2Date(time, format)); + } + + /** + * 获取年份中的第几周 + *

注意:国外周日才是新的一周的开始

+ * + * @param date Date类型时间 + * @return 1...54 + */ + public static int getWeekOfYear(final Date date) { + Calendar cal = Calendar.getInstance(); + cal.setTime(date); + return cal.get(Calendar.WEEK_OF_YEAR); + } + + /** + * 获取年份中的第几周 + *

注意:国外周日才是新的一周的开始

+ * + * @param millis 毫秒时间戳 + * @return 1...54 + */ + public static int getWeekOfYear(final long millis) { + return getWeekOfYear(millis2Date(millis)); + } + + private static final String[] CHINESE_ZODIAC = {"猴", "鸡", "狗", "猪", "鼠", "牛", "虎", "兔", "龙", "蛇", "马", "羊"}; + + /** + * 获取生肖 + *

time格式为yyyy-MM-dd HH:mm:ss

+ * + * @param time 时间字符串 + * @return 生肖 + */ + public static String getChineseZodiac(final String time) { + return getChineseZodiac(string2Date(time, DEFAULT_FORMAT)); + } + + /** + * 获取生肖 + *

time格式为format

+ * + * @param time 时间字符串 + * @param format 时间格式 + * @return 生肖 + */ + public static String getChineseZodiac(final String time, final DateFormat format) { + return getChineseZodiac(string2Date(time, format)); + } + + /** + * 获取生肖 + * + * @param date Date类型时间 + * @return 生肖 + */ + public static String getChineseZodiac(final Date date) { + Calendar cal = Calendar.getInstance(); + cal.setTime(date); + return CHINESE_ZODIAC[cal.get(Calendar.YEAR) % 12]; + } + + /** + * 获取生肖 + * + * @param millis 毫秒时间戳 + * @return 生肖 + */ + public static String getChineseZodiac(final long millis) { + return getChineseZodiac(millis2Date(millis)); + } + + /** + * 获取生肖 + * + * @param year 年 + * @return 生肖 + */ + public static String getChineseZodiac(final int year) { + return CHINESE_ZODIAC[year % 12]; + } + + private static final String[] ZODIAC = {"水瓶座", "双鱼座", "白羊座", "金牛座", "双子座", "巨蟹座", "狮子座", "处女座", "天秤座", "天蝎座", "射手座", "魔羯座"}; + private static final int[] ZODIAC_FLAGS = {20, 19, 21, 21, 21, 22, 23, 23, 23, 24, 23, 22}; + + /** + * 获取星座 + *

time格式为yyyy-MM-dd HH:mm:ss

+ * + * @param time 时间字符串 + * @return 生肖 + */ + public static String getZodiac(final String time) { + return getZodiac(string2Date(time, DEFAULT_FORMAT)); + } + + /** + * 获取星座 + *

time格式为format

+ * + * @param time 时间字符串 + * @param format 时间格式 + * @return 生肖 + */ + public static String getZodiac(final String time, final DateFormat format) { + return getZodiac(string2Date(time, format)); + } + + /** + * 获取星座 + * + * @param date Date类型时间 + * @return 星座 + */ + public static String getZodiac(final Date date) { + Calendar cal = Calendar.getInstance(); + cal.setTime(date); + int month = cal.get(Calendar.MONTH) + 1; + int day = cal.get(Calendar.DAY_OF_MONTH); + return getZodiac(month, day); + } + + /** + * 获取星座 + * + * @param millis 毫秒时间戳 + * @return 星座 + */ + public static String getZodiac(final long millis) { + return getZodiac(millis2Date(millis)); + } + + /** + * 获取星座 + * + * @param month 月 + * @param day 日 + * @return 星座 + */ + public static String getZodiac(final int month, final int day) { + return ZODIAC[day >= ZODIAC_FLAGS[month - 1] + ? month - 1 + : (month + 10) % 12]; + } + + private static long timeSpan2Millis(final long timeSpan, @TimeConstants.Unit final int unit) { + return timeSpan * unit; + } + + private static long millis2TimeSpan(final long millis, @TimeConstants.Unit final int unit) { + return millis / unit; + } + + private static String millis2FitTimeSpan(long millis, int precision) { + if (millis < 0 || precision <= 0) return null; + precision = Math.min(precision, 5); + String[] units = {"天", "小时", "分钟", "秒", "毫秒"}; + if (millis == 0) return 0 + units[precision - 1]; + StringBuilder sb = new StringBuilder(); + int[] unitLen = {86400000, 3600000, 60000, 1000, 1}; + for (int i = 0; i < precision; i++) { + if (millis >= unitLen[i]) { + long mode = millis / unitLen[i]; + millis -= mode * unitLen[i]; + sb.append(mode).append(units[i]); + } + } + return sb.toString(); + } + + @SuppressLint("SimpleDateFormat") + public static String generateTimeStr(String prefix) { + SimpleDateFormat formatter = new SimpleDateFormat("_yyyy-MM-dd_HH-mm-ss"); + return prefix + formatter.format(new Date()); + } + + /** + * 格式化时间 + * + * @param time 时间戳 毫秒 + */ + @SuppressLint("SimpleDateFormat") + public static String fromatTimeStamp(long time) { + Date date = new Date(time); + SimpleDateFormat formatter = new SimpleDateFormat("yyyy-MM-dd HH:mm"); + return formatter.format(date); + } + + @SuppressLint("SimpleDateFormat") + public static String formatTimeStampWithSecond(long time) { + Date date = new Date(time); + SimpleDateFormat formatter = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); + return formatter.format(date); + } + +} diff --git a/app/src/main/java/cn/org/landcloud/survey/util/Utils.java b/app/src/main/java/cn/org/landcloud/survey/util/Utils.java new file mode 100644 index 0000000..77854dd --- /dev/null +++ b/app/src/main/java/cn/org/landcloud/survey/util/Utils.java @@ -0,0 +1,31 @@ +package cn.org.landcloud.survey.util; + +import java.nio.charset.StandardCharsets; + +import cn.org.landcloud.security.Util; +import cn.org.landcloud.security.sm2.SM2; +import cn.org.landcloud.security.sm2.SM2EncDecUtils; +import cn.org.landcloud.security.sm2.SM2SignVO; +import cn.org.landcloud.security.sm2.SM2SignVerUtils; +import cn.org.landcloud.security.sm3.SM3Utils; + +public class Utils { + + + /** + * 生成附件校验码 + * @param content + * @param privateKey + * @return + */ + public static String makeJYM(String content,String privateKey) { + String hash = SM3Utils.sm3(content); + try { + SM2SignVO sm2SignVO = SM2SignVerUtils.Sign2SM2(Util.hexStringToBytes(privateKey),hash.getBytes(StandardCharsets.UTF_8)); + return sm2SignVO.getSm2_signForSoft(); + } catch (Exception e) { + e.printStackTrace(); + } + return null; + } +} diff --git a/app/src/main/res/drawable-v24/ic_launcher_foreground.xml b/app/src/main/res/drawable-v24/ic_launcher_foreground.xml new file mode 100644 index 0000000..2b068d1 --- /dev/null +++ b/app/src/main/res/drawable-v24/ic_launcher_foreground.xml @@ -0,0 +1,30 @@ + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/ic_launcher_background.xml b/app/src/main/res/drawable/ic_launcher_background.xml new file mode 100644 index 0000000..07d5da9 --- /dev/null +++ b/app/src/main/res/drawable/ic_launcher_background.xml @@ -0,0 +1,170 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/app/src/main/res/layout/activity_main.xml b/app/src/main/res/layout/activity_main.xml new file mode 100644 index 0000000..4c2c2ae --- /dev/null +++ b/app/src/main/res/layout/activity_main.xml @@ -0,0 +1,71 @@ + + + +