From 00f4e4fc6e53a26cf3dc67d57d8b00536634d707 Mon Sep 17 00:00:00 2001
From: 张世豪 <979909237@qq.com>
Date: 星期五, 26 十二月 2025 17:36:11 +0800
Subject: [PATCH] 优化了注册账号
---
src/sendMQTT/Server.java | 82 +
dikuai.properties | 10
src/login/HttpClientLoca.java | 236 ++++
src/lujing/YixinglujingHaveObstacel.java | 610 ++++++----
src/sendMQTT/HTTPUtils/MovePathCommand.java | 58 +
set.properties | 8
src/login/ApiConfig.java | 93 +
src/login/LoginVerifier.java | 245 ++++
src/login/ApiResponse.java | 76 +
user.properties | 10
Obstacledge.properties | 2
src/sendMQTT/HTTPUtils/PropertiesFileUploader.java | 337 +++++
src/dikuai/Dikuaiguanli.java | 7
src/login/PasswordReset.java | 273 ++++
src/set/Sets.java | 44
src/denglu/RegistrationFrame.java | 320 ++++-
src/login/LoginTestRunner.java | 106 +
src/sendMQTT/HTTPUtils/FileUploadResponse.java | 111 +
src/login/EmailCodeSender.java | 134 ++
src/denglu/Denglu.java | 169 ++
src/login/UserRegister.java | 280 ++++
src/lujing/AoxinglujingHaveObstacel.java | 25
src/user/ZhaohuiMima.java | 172 ++
23 files changed, 2,932 insertions(+), 476 deletions(-)
diff --git a/Obstacledge.properties b/Obstacledge.properties
index 73d7371..c98c415 100644
--- a/Obstacledge.properties
+++ b/Obstacledge.properties
@@ -1,5 +1,5 @@
# 鍓茶崏鏈哄湴鍧楅殰纰嶇墿閰嶇疆鏂囦欢
-# 鐢熸垚鏃堕棿锛�2025-12-26T15:36:20.593959500
+# 鐢熸垚鏃堕棿锛�2025-12-26T16:29:19.993693300
# 鍧愭爣绯伙細WGS84锛堝害鍒嗘牸寮忥級
# ============ 鍦板潡鍩哄噯绔欓厤缃� ============
diff --git a/dikuai.properties b/dikuai.properties
index 79cef9e..edaa106 100644
--- a/dikuai.properties
+++ b/dikuai.properties
@@ -1,5 +1,5 @@
#Dikuai Properties
-#Fri Dec 26 15:36:20 CST 2025
+#Fri Dec 26 16:29:20 CST 2025
LAND1.angleThreshold=-1
LAND1.baseStationCoordinates=3949.89151752,N,11616.79267501,E
LAND1.boundaryCoordinates=4.30,87.65;-2.36,-65.51;44.25,-66.72;49.70,-14.05;98.13,-15.87;99.34,-69.75;137.48,-67.93;134.45,90.07;4.30,87.65
@@ -16,11 +16,11 @@
LAND1.mowingPattern=骞宠绾�
LAND1.mowingSafetyDistance=0.53
LAND1.mowingTrack=-1
-LAND1.mowingWidth=50
-LAND1.obstacleCoordinates=25.17,9.94;17.74,67.19;113.88,72.00;120.00,19.12;74.99,-4.48
-LAND1.plannedPath=138.019779,-68.434845;137.127629,-21.913485;136.166686,28.195080;135.316239,72.541818;134.969746,90.609756;111.243743,90.168596;15.523233,88.388776;3.792139,88.170648;2.824293,65.913086;0.722058,17.568015;-1.965221,-44.231336;-2.912931,-66.025824;35.693486,-67.028051;44.726689,-67.262553;49.925119,-17.023781;50.176098,-14.598266;54.258476,-14.751682;97.611339,-16.380883;98.822337,-70.305305;129.645759,-68.834445;138.019779,-68.434845;137.769962,-68.446766;136.876187,-21.840707;135.919129,28.065280;135.066433,72.529320;134.719790,90.605108;134.219876,90.595813;134.566820,72.504324;135.424016,27.805678;136.373304,-21.695151;137.270327,-68.470608;136.770692,-68.494450;135.870421,-21.549596;134.928902,27.546076;134.067208,72.479327;133.719962,90.586517;133.220049,90.577222;133.567595,72.454331;134.433789,27.286474;135.367537,-21.404040;136.271057,-68.518293;135.771423,-68.542135;134.864654,-21.258485;133.938675,27.026872;133.067983,72.429335;132.720135,90.567927;132.220221,90.558631;132.568370,72.404339;133.443562,26.767270;134.361771,-21.112929;135.271788,-68.565977;134.772153,-68.589819;133.858887,-20.967374;132.948448,26.507669;132.068757,72.379343;131.720308,90.549336;131.220394,90.540041;131.569145,72.354346;132.453335,26.248067;133.356004,-20.821818;134.272519,-68.613661;133.772884,-68.637503;132.853121,-20.676263;131.958221,25.988465;131.069532,72.329350;130.720480,90.530745;130.220567,90.521450;130.569920,72.304354;131.463108,25.728863;132.350238,-20.530707;133.273249,-68.661345;132.773615,-68.685187;131.847354,-20.385152;130.967994,25.469261;130.070307,72.279358;129.720653,90.512154;129.220739,90.502859;129.570695,72.254361;130.472881,25.209659;131.344471,-20.239596;132.273980,-68.709029;131.774345,-68.732871;130.841588,-20.094040;129.977767,24.950058;129.071082,72.229365;128.720826,90.493564;128.220912,90.484268;128.571469,72.204369;129.482654,24.690456;130.338705,-19.948485;131.274710,-68.756713;130.775076,-68.780555;129.835821,-19.802929;128.987540,24.430854;128.071857,72.179373;127.720998,90.474973;127.221084,90.465678;127.572244,72.154377;128.492427,24.171252;129.332938,-19.657374;130.275441,-68.804397;129.775806,-68.828239;128.830055,-19.511818;127.997313,23.911650;127.072632,72.129380;126.721171,90.456382;126.221257,90.447087;126.573019,72.104384;127.502200,23.652048;128.327171,-19.366263;129.202362,-65.003264;129.276172,-68.852081;128.776537,-68.875923;128.602946,-59.823997;127.824288,-19.220707;127.007086,23.392447;126.073407,72.079388;125.721343,90.437792;125.221430,90.428496;125.573794,72.054392;126.511973,23.132845;127.321405,-19.075152;128.003530,-54.644731;128.276902,-68.899765;127.777267,-68.923607;127.404114,-49.465465;126.818522,-18.929596;126.016859,22.873243;125.074181,72.029395;124.721516,90.419201;124.221602,90.409906;124.574569,72.004399;125.521746,22.613641;126.315638,-18.784041;126.804699,-44.286199;127.277633,-68.947449;126.777998,-68.971291;126.205283,-39.106932;125.812755,-18.638485;125.026633,22.354039;124.074956,71.979403;123.721689,90.400610;123.221775,90.391315;123.575344,71.954407;124.531519,22.094437;125.309872,-18.492930;125.605867,-33.927666;126.278363,-68.995133;125.778729,-69.018975;125.006451,-28.748400;124.806988,-18.347374;124.036406,21.834836;123.075731,71.929411;122.721861,90.382019;122.221948,90.372724;122.576119,71.904414;123.541292,21.575234;124.304105,-18.201818;124.407035,-23.569134;125.279094,-69.042817;124.779459,-69.066659;123.807619,-18.389867;123.801222,-18.056263;123.046179,21.315632;122.076506,71.879418;121.722034,90.363429;121.222120,90.354133;121.576893,71.854422;122.551065,21.056030;123.208204,-13.210601;123.298339,-17.910707;124.279824,-69.090501;123.780190,-69.114343;122.795455,-17.765152;122.608788,-8.031335;122.055952,20.796428;121.077281,71.829426;120.722207,90.344838;120.222293,90.335543;120.577668,71.804429;121.560838,20.536826;122.009372,-2.852069;122.292572,-17.619596;123.280555,-69.138185;122.780920,-69.162027;121.789689,-17.474041;121.409956,2.327198;121.065725,20.277225;120.078056,71.779433;119.722379,90.326247;119.222466,90.316952;119.578443,71.754437;120.570611,20.017623;120.810540,7.506464;121.286805,-17.328485;122.281286,-69.185869;121.781651,-69.209712;120.783922,-17.182930;120.211124,12.685730;120.075498,19.758021;119.078830,71.729441;118.722552,90.307657;118.222638,90.298361;118.579218,71.704445;119.580384,19.498419;119.611709,17.864996;120.281039,-17.037374;121.282016,-69.233554;120.782382,-69.257396;119.778156,-16.891819;119.085271,19.238817;119.012293,23.044263;118.079605,71.679448;117.722725,90.289066;117.222811,90.279770;117.579993,71.654452;118.412877,28.223529;118.590157,18.979215;119.275272,-16.746263;120.282747,-69.281238;119.783112,-69.305080;118.772389,-16.600708;118.095044,18.719614;117.813461,33.402795;117.080380,71.629456;116.722897,90.270475;116.222984,90.261180;116.580768,71.604460;117.214045,38.582061;117.599930,18.460012;118.269506,-16.455152;119.283477,-69.328922;118.783843,-69.352764;117.766622,-16.309596;117.104817,18.200410;116.614629,43.761327;116.081155,71.579464;115.723070,90.251884;115.223156,90.242589;115.581542,71.554467;116.015214,48.940594;116.609703,17.940808;117.263739,-16.164041;118.284208,-69.376606;117.784573,-69.400448;116.760856,-16.018485;116.114590,17.681206;115.415798,54.119860;115.081930,71.529471;114.723243,90.233294;114.223329,90.223998;114.582317,71.504475;114.816382,59.299126;115.619476,17.421604;116.257973,-15.872930;117.284939,-69.424290;116.785304,-69.448132;115.755089,-15.727374;115.124363,17.162003;114.216966,64.478392;114.082705,71.479479;113.723415,90.214703;113.223502,90.205408;113.583092,71.454482;113.617550,69.657659;114.629249,16.902401;115.252206,-15.581819;116.285669,-69.471974;115.786034,-69.495816;114.749323,-15.436263;114.134136,16.642799;113.083480,71.429486;113.018134,74.836925;112.723588,90.196112;112.223674,90.186817;112.418719,80.016191;112.583867,71.404490;113.639022,16.383197;114.246439,-15.290708;115.286400,-69.519658;114.786765,-69.543500;113.743556,-15.145152;113.143909,16.123595;112.084254,71.379494;111.819303,85.195457;111.723761,90.177522;111.243743,90.168596;111.223847,90.168226;111.584642,71.354498;112.648795,15.863993;113.240673,-14.999597;114.287130,-69.567342;113.787496,-69.591184;112.737790,-14.854041;112.153682,15.604392;111.085029,71.329501;110.723933,90.158931;110.224020,90.149635;110.585417,71.304505;111.658568,15.344790;112.234906,-14.708485;113.287861,-69.615026;112.788226,-69.638868;111.732023,-14.562930;111.163455,15.085188;110.085804,71.279509;109.724106,90.140340;109.224192,90.131045;109.586192,71.254513;110.668341,14.825586;111.229140,-14.417374;112.288591,-69.662710;111.788957,-69.686552;110.726256,-14.271819;110.173228,14.565984;109.086579,71.229516;108.724279,90.121749;108.224365,90.112454;108.586966,71.204520;109.678114,14.306382;110.223373,-14.126263;111.289322,-69.710394;110.789687,-69.734236;109.720490,-13.980708;109.183001,14.046781;108.087354,71.179524;107.724451,90.103159;107.224538,90.093863;107.587741,71.154528;108.687887,13.787179;109.217607,-13.835152;110.290053,-69.758078;109.790418,-69.781920;108.714723,-13.689597;108.192774,13.527577;107.088129,71.129532;106.724624,90.084568;106.224710,90.075273;106.588516,71.104535;107.697660,13.267975;108.211840,-13.544041;109.290783,-69.805762;108.791148,-69.829604;107.708957,-13.398486;107.202547,13.008373;106.088904,71.079539;105.724797,90.065977;105.224883,90.056682;105.589291,71.054543;106.707433,12.748771;107.206074,-13.252930;108.291514,-69.853446;107.791879,-69.877288;106.703190,-13.107375;106.212320,12.489170;105.089678,71.029547;104.724969,90.047386;104.225055,90.038091;104.590066,71.004550;105.717206,12.229568;106.200307,-12.961819;107.292244,-69.901130;106.792610,-69.924973;105.697424,-12.816263;105.222093,11.969966;104.090453,70.979554;103.725142,90.028796;103.225228,90.019500;103.590841,70.954558;104.726979,11.710364;105.194540,-12.670708;106.292975,-69.948815;105.793340,-69.972657;104.691657,-12.525152;104.231866,11.450762;103.091228,70.929562;102.725314,90.010205;102.225401,90.000910;102.591616,70.904566;103.736752,11.191160;104.188774,-12.379597;105.293706,-69.996499;104.794071,-70.020341;103.685891,-12.234041;103.241639,10.931559;102.092003,70.879569;101.725487,89.991614;101.225573,89.982319;101.592390,70.854573;102.746525,10.671957;103.183007,-12.088486;104.294436,-70.044183;103.794801,-70.068025;102.680124,-11.942930;102.251412,10.412355;101.092778,70.829577;100.725660,89.973024;100.225746,89.963728;100.593165,70.804581;101.756298,10.152753;102.177241,-11.797375;103.295167,-70.091867;102.795532,-70.115709;101.674357,-11.651819;101.261185,9.893151;100.093553,70.779585;99.725832,89.954433;99.225919,89.945138;99.593940,70.754588;100.766071,9.633549;101.171474,-11.506264;102.295897,-70.139551;101.796263,-70.163393;100.668591,-11.360708;100.270958,9.373948;99.094327,70.729592;98.726005,89.935842;98.226091,89.926547;98.594715,70.704596;99.775844,9.114346;100.165708,-11.215153;101.296628,-70.187235;100.796993,-70.211077;99.662824,-11.069597;99.280731,8.854744;98.095102,70.679600;97.726178,89.917251;97.226264,89.907956;97.595490,70.654603;98.785617,8.595142;99.159941,-10.924041;100.297358,-70.234919;99.797724,-70.258761;98.657058,-10.778486;98.290504,8.335540;97.095877,70.629607;96.726350,89.898661;96.226437,89.889365;96.596265,70.604611;97.795390,8.075939;98.154174,-10.632930;99.298089,-70.282603;98.658673,-63.017540;97.651291,-10.487375;97.300277,7.816337;96.096652,70.579615;95.726523,89.880070;95.226609,89.870775;95.597039,70.554619;96.805163,7.556735;97.148408,-10.341819;97.263970,-16.367829;96.763517,-16.349022;96.645525,-10.196264;96.310050,7.297133;95.097427,70.529622;94.726696,89.861479;94.226782,89.852184;94.597814,70.504626;95.814936,7.037531;96.142641,-10.050708;96.263065,-16.330215;95.762612,-16.311408;95.639758,-9.905153;95.319823,6.777929;94.098202,70.479630;93.726868,89.842889;93.226955,89.833593;93.598589,70.454634;94.824709,6.518328;95.136875,-9.759597;95.262160,-16.292601;94.761707,-16.273794;94.633991,-9.614042;94.329596,6.258726;93.098977,70.429637;92.727041,89.824298;92.227127,89.815002;92.599364,70.404641;93.834482,5.999124;94.131108,-9.468486;94.261254,-16.254987;93.760802,-16.236180;93.628225,-9.322931;93.339369,5.739522;92.099751,70.379645;91.727214,89.805707;91.227300,89.796412;91.600139,70.354649;92.844255,5.479920;93.125342,-9.177375;93.260349,-16.217373;92.759897,-16.198566;92.622458,-9.031819;92.349142,5.220318;91.100526,70.329653;90.727386,89.787116;90.227473,89.777821;90.600914,70.304656;91.854028,4.960717;92.119575,-8.886264;92.259444,-16.179759;91.758991,-16.160952;91.616692,-8.740708;91.358915,4.701115;90.101301,70.279660;89.727559,89.768526;89.227645,89.759230;89.601689,70.254664;90.863802,4.441513;91.113808,-8.595153;91.258539,-16.142145;90.758086,-16.123338;90.610925,-8.449597;90.368688,4.181911;89.102076,70.229668;88.727732,89.749935;88.227818,89.740640;88.602463,70.204671;89.873575,3.922309;90.108042,-8.304042;90.257634,-16.104530;89.757181,-16.085723;89.605159,-8.158486;89.378461,3.662707;88.102851,70.179675;87.727904,89.731344;87.227991,89.722049;87.603238,70.154679;88.883348,3.403106;89.102275,-8.012931;89.256728,-16.066916;88.756276,-16.048109;88.599392,-7.867375;88.388234,3.143504;87.103626,70.129683;86.728077,89.712754;86.228163,89.703458;86.604013,70.104687;87.893121,2.883902;88.096509,-7.721820;88.255823,-16.029302;87.755371,-16.010495;87.593625,-7.576264;87.398007,2.624300;86.104401,70.079690;85.728250,89.694163;85.228336,89.684867;85.604788,70.054694;86.902894,2.364698;87.090742,-7.430709;87.254918,-15.991688;86.754465,-15.972881;86.587859,-7.285153;86.407780,2.105096;85.105175,70.029698;84.728422,89.675572;84.228509,89.666277;84.605563,70.004702;85.912667,1.845495;86.084976,-7.139597;86.254013,-15.954074;85.753560,-15.935267;85.582092,-6.994042;85.417553,1.585893;84.105950,69.979706;83.728595,89.656981;83.228681,89.647686;83.606338,69.954709;84.922440,1.326291;85.079209,-6.848486;85.253108,-15.916460;84.752655,-15.897653;84.576326,-6.702931;84.427326,1.066689;83.106725,69.929713;82.728768,89.638391;82.228854,89.629095;82.607112,69.904717;83.932213,0.807087;84.073442,-6.557375;84.252202,-15.878846;83.751750,-15.860039;83.570559,-6.411820;83.437099,0.547485;82.107500,69.879721;81.728940,89.619800;81.229027,89.610505;81.607887,69.854724;82.941986,0.287884;83.067676,-6.266264;83.251297,-15.841232;82.750845,-15.822425;82.564793,-6.120709;82.446872,0.028282;81.108275,69.829728;80.729113,89.601209;80.229199,89.591914;80.608662,69.804732;81.951759,-0.231320;82.061909,-5.975153;82.250392,-15.803618;81.749939,-15.784811;81.559026,-5.829598;81.456645,-0.490922;80.109050,69.779736;79.729285,89.582618;79.229372,89.573323;79.609437,69.754740;80.961532,-0.750524;81.056143,-5.684042;81.249487,-15.766004;80.749034,-15.747197;80.553260,-5.538487;80.466418,-1.010126;79.109824,69.729743;78.729458,89.564028;78.229544,89.554732;78.610212,69.704747;79.971305,-1.269727;80.050376,-5.392931;80.248582,-15.728390;79.748129,-15.709583;79.547493,-5.247375;79.476191,-1.529329;78.110599,69.679751;77.729631,89.545437;77.229717,89.536142;77.610987,69.654755;78.981078,-1.788931;79.044610,-5.101820;79.247676,-15.690776;78.747224,-15.671969;78.541726,-4.956264;78.485964,-2.048533;77.111374,69.629758;76.729803,89.526846;76.229890,89.517551;76.611762,69.604762;77.990851,-2.308135;78.038843,-4.810709;78.246771,-15.653162;77.746319,-15.634355;77.535960,-4.665153;77.495737,-2.567737;76.112149,69.579766;75.729976,89.508256;75.230062,89.498960;75.612536,69.554770;77.000624,-2.827338;77.033077,-4.519598;77.245866,-15.615548;76.745413,-15.596741;76.530193,-4.374042;76.505510,-3.086940;75.112924,69.529774;74.730149,89.489665;74.230235,89.480370;74.613311,69.504777;76.010397,-3.346542;76.027310,-4.228487;76.244961,-15.577934;75.744508,-15.559127;75.524427,-4.082931;75.515283,-3.606144;74.113699,69.479781;73.730321,89.471074;73.230408,89.461779;73.614086,69.454785;75.020170,-3.865746;75.021543,-3.937376;75.244056,-15.540320;74.743603,-15.521513;74.525056,-4.125348;74.518660,-3.791820;73.114474,69.429789;72.730494,89.452483;72.230580,89.443188;72.614861,69.404792;74.015777,-3.646265;74.029943,-4.384949;74.243150,-15.502706;73.742698,-15.483899;73.534829,-4.644551;73.512894,-3.500709;72.115248,69.379796;71.730667,89.433893;71.230753,89.424597;71.615636,69.354800;73.010010,-3.355153;73.039716,-4.904153;73.242245,-15.465092;72.741793,-15.446285;72.544602,-5.163755;72.507127,-3.209598;71.116023,69.329804;70.730839,89.415302;70.230926,89.406007;70.616411,69.304808;72.004244,-3.064042;72.049489,-5.423357;72.241340,-15.427478;71.740887,-15.408671;71.554375,-5.682959;71.501360,-2.918487;70.116798,69.279811;69.731012,89.396711;69.231098,89.387416;69.617186,69.254815;70.998477,-2.772931;71.059262,-5.942560;71.240435,-15.389864;70.739982,-15.371057;70.564148,-6.202162;70.495594,-2.627376;69.117573,69.229819;68.731185,89.378121;68.231271,89.368825;68.617960,69.204823;69.992711,-2.481820;70.069035,-6.461764;70.239530,-15.352250;69.739077,-15.333443;69.573921,-6.721366;69.489827,-2.336265;68.118348,69.179827;67.731357,89.359530;67.231444,89.350234;67.618735,69.154830;68.986944,-2.190709;69.078808,-6.980968;69.238624,-15.314636;68.738172,-15.295829;68.583694,-7.240570;68.484061,-2.045154;67.119123,69.129834;66.731530,89.340939;66.231616,89.331644;66.619510,69.104838;67.981177,-1.899598;68.088581,-7.500171;68.237719,-15.277022;67.737267,-15.258215;67.593467,-7.759773;67.478294,-1.754043;66.119898,69.079842;65.731703,89.322348;65.231789,89.313053;65.620285,69.054845;66.975411,-1.608487;67.098354,-8.019375;67.236814,-15.239408;66.736361,-15.220601;66.603240,-8.278977;66.472528,-1.462931;65.120672,69.029849;64.731875,89.303758;64.231962,89.294462;64.621060,69.004853;65.969644,-1.317376;66.108127,-8.538579;66.235909,-15.201794;65.735456,-15.182987;65.613013,-8.798181;65.466761,-1.171820;64.121447,68.979857;63.732048,89.285167;63.232134,89.275872;63.621835,68.954861;64.963878,-1.026265;65.117900,-9.057782;65.235004,-15.164180;64.734551,-15.145373;64.622786,-9.317384;64.460994,-0.880709;63.122222,68.929864;62.732221,89.266576;62.232307,89.257281;62.622609,68.904868;63.958111,-0.735154;64.127673,-9.576986;64.234098,-15.126566;63.733646,-15.107759;63.632559,-9.836588;63.455228,-0.589598;62.122997,68.879872;61.732393,89.247986;61.232480,89.238690;61.623384,68.854876;62.952345,-0.444043;63.137446,-10.096190;63.233193,-15.088952;62.732741,-15.070145;62.642332,-10.355792;62.449461,-0.298487;61.123772,68.829879;60.732566,89.229395;60.232652,89.220099;60.624159,68.804883;61.946578,-0.152932;62.147219,-10.615393;62.232288,-15.051338;61.731835,-15.032531;61.652105,-10.874995;61.443695,-0.007376;60.124547,68.779887;59.732739,89.210804;59.232825,89.201509;59.624934,68.754891;60.940811,0.138179;61.156992,-11.134597;61.231383,-15.013724;60.730930,-14.994917;60.661878,-11.394199;60.437928,0.283735;59.125321,68.729895;58.732911,89.192213;58.232998,89.182918;58.625709,68.704898;59.935045,0.429291;60.166765,-11.653801;60.230478,-14.976110;59.730025,-14.957303;59.671651,-11.913403;59.432162,0.574846;58.126096,68.679902;57.733084,89.173623;57.233170,89.164327;57.626484,68.654906;58.929278,0.720402;59.176538,-12.173004;59.229572,-14.938496;58.729120,-14.919689;58.681424,-12.432606;58.426395,0.865957;57.126871,68.629910;56.733256,89.155032;56.233343,89.145737;56.627259,68.604913;57.923512,1.011513;58.186311,-12.692208;58.228667,-14.900882;57.728215,-14.882075;57.691197,-12.951810;57.420629,1.157068;56.127646,68.579917;55.733429,89.136441;55.233515,89.127146;55.628033,68.554921;56.917745,1.302624;57.196084,-13.211412;57.227762,-14.863268;56.727309,-14.844460;56.700971,-13.471013;56.414862,1.448179;55.128421,68.529925;54.733602,89.117850;54.233688,89.108555;54.628808,68.504929;55.911979,1.593735;56.205857,-13.730615;56.226857,-14.825653;55.726404,-14.806846;55.710744,-13.990217;55.409095,1.739290;54.129196,68.479932;53.733774,89.099260;53.233861,89.089964;53.629583,68.454936;54.906212,1.884846;55.215630,-14.249819;55.225952,-14.788039;54.725499,-14.769232;54.720517,-14.509421;54.403329,2.030401;53.129971,68.429940;52.733947,89.080669;52.234033,89.071374;52.630358,68.404944;53.900446,2.175957;54.225046,-14.750425;53.724594,-14.731618;53.397562,2.321513;52.130745,68.379948;51.734120,89.062078;51.234206,89.052783;51.631133,68.354951;52.894679,2.467068;53.224141,-14.712811;52.723689,-14.694004;52.391796,2.612624;51.131520,68.329955;50.734292,89.043488;50.234379,89.034192;50.631908,68.304959;51.888912,2.758179;52.223236,-14.675197;51.722783,-14.656390;51.386029,2.903735;50.132295,68.279963;49.734465,89.024897;49.234551,89.015602;49.632683,68.254966;50.883146,3.049290;51.222331,-14.637583;50.721878,-14.618776;50.380263,3.194846;49.133070,68.229970;48.734638,89.006306;48.234724,88.997011;48.633457,68.204974;49.877379,3.340401;50.221426,-14.599969;49.941883,-17.014992;49.792411,-18.306305;49.769382,-17.105439;49.374496,3.485957;48.133845,68.179978;47.734810,88.987715;47.234897,88.978420;47.634232,68.154982;48.871613,3.631512;49.274268,-17.365041;49.370511,-22.383640;48.948611,-26.460975;48.779155,-17.624643;48.368729,3.777068;47.134620,68.129985;46.734983,88.969125;46.235069,88.959829;46.635007,68.104989;47.865846,3.922623;48.284041,-17.884245;48.526711,-30.538309;48.104811,-34.615644;47.788928,-18.143846;47.362963,4.068179;46.135395,68.079993;45.735156,88.950534;45.235242,88.941239;45.635782,68.054997;46.860080,4.213735;47.293814,-18.403448;47.682911,-38.692978;47.261011,-42.770313;46.798701,-18.663050;46.357196,4.359290;45.136169,68.030000;44.735328,88.931943;44.235415,88.922648;44.636557,68.005004;45.854313,4.504846;46.303587,-18.922652;46.839111,-46.847647;46.417211,-50.924982;45.808474,-19.182254;45.351430,4.650401;44.136944,67.980008;43.735501,88.913353;43.235587,88.904057;43.637332,67.955012;44.848546,4.795957;45.313360,-19.441856;45.995311,-55.002317;45.573411,-59.079651;44.818247,-19.701457;44.345663,4.941512;43.137719,67.930016;42.735674,88.894762;42.235760,88.885466;42.638106,67.905019;43.842780,5.087068;44.323133,-19.961059;45.151511,-63.156986;44.729611,-67.234320;43.828020,-20.220661;43.339897,5.232623;42.138494,67.880023;41.735846,88.876171;41.235933,88.866876;41.638881,67.855027;42.837013,5.378179;43.332906,-20.480263;44.229813,-67.249655;43.729472,-67.236666;42.837793,-20.739865;42.334130,5.523734;41.139269,67.830031;40.736019,88.857580;40.236105,88.848285;40.639656,67.805034;41.831247,5.669290;42.342679,-20.999467;43.229131,-67.223677;42.728790,-67.210688;41.847566,-21.259068;41.328363,5.814845;40.140044,67.780038;39.736192,88.838990;39.236278,88.829694;39.640431,67.755042;40.825480,5.960401;41.352452,-21.518670;42.228449,-67.197699;41.728108,-67.184710;40.857339,-21.778272;40.322597,6.105957;39.140818,67.730046;38.736364,88.820399;38.236451,88.811104;38.641206,67.705050;39.819714,6.251512;40.362225,-22.037874;41.227767,-67.171721;40.727426,-67.158732;39.867112,-22.297476;39.316830,6.397068;38.141593,67.680053;37.736537,88.801808;37.236623,88.792513;37.641981,67.655057;38.813947,6.542623;39.371998,-22.557078;40.227085,-67.145743;39.726744,-67.132754;38.876885,-22.816679;38.311064,6.688179;37.142368,67.630061;36.736710,88.783218;36.236796,88.773922;36.642756,67.605065;37.808180,6.833734;38.381771,-23.076281;39.226403,-67.119765;38.726062,-67.106777;37.886658,-23.335883;37.305297,6.979290;36.143143,67.580068;35.736882,88.764627;35.236969,88.755331;35.643530,67.555072;36.802414,7.124845;37.391544,-23.595485;38.225721,-67.093788;37.725380,-67.080799;36.896431,-23.855087;36.299531,7.270401;35.143918,67.530076;34.737055,88.746036;34.237141,88.736741;34.644305,67.505080;35.796647,7.415956;36.401317,-24.114689;37.225039,-67.067810;36.724698,-67.054821;35.906204,-24.374290;35.293764,7.561512;34.144693,67.480084;33.737227,88.727445;33.237314,88.718150;33.645080,67.455087;34.790881,7.707067;35.411090,-24.633892;36.224357,-67.041832;35.724015,-67.028843;34.915977,-24.893494;34.287997,7.852623;33.145468,67.430091;32.737400,88.708855;32.237486,88.699559;32.645855,67.405095;33.785114,7.998179;34.420863,-25.153096;35.142490,-62.782491;35.223674,-67.015854;34.723333,-67.002865;34.555690,-58.261045;33.925750,-25.412698;33.282231,8.143734;32.146242,67.380099;31.737573,88.690264;31.237659,88.680969;31.646630,67.355103;32.779348,8.289290;33.430636,-25.672300;33.968889,-53.739600;34.222992,-66.989876;33.722651,-66.976888;33.382088,-49.218155;32.935523,-25.931901;32.276464,8.434845;31.147017,67.330106;30.737745,88.671673;30.237832,88.662378;30.647405,67.305110;31.773581,8.580401;32.440409,-26.191503;32.795288,-44.696710;33.222310,-66.963899;32.721969,-66.950910;32.208487,-40.175265;31.945296,-26.451105;31.270698,8.725956;30.147792,67.280114;29.737918,88.653082;29.238004,88.643787;29.648180,67.255118;30.767815,8.871512;31.450182,-26.710707;31.621686,-35.653819;32.221628,-66.937921;31.721287,-66.924932;31.034886,-31.132374;30.955069,-26.970309;30.264931,9.017067;29.148567,67.230121;28.738091,88.634492;28.238177,88.625196;28.648954,67.205125;29.762048,9.162623;30.448085,-26.610929;30.459955,-27.229911;31.220946,-66.911943;30.720605,-66.898954;29.964842,-27.489512;29.861284,-22.089484;29.259165,9.308178;28.149342,67.180129;27.738263,88.615901;27.238350,88.606606;27.649729,67.155133;28.756281,9.453734;29.274484,-17.568039;29.469728,-27.749114;30.220264,-66.885965;29.719923,-66.872976;28.974615,-28.008716;28.687683,-13.046593;28.253398,9.599289;27.150117,67.130137;26.738436,88.597310;26.238522,88.588015;26.650504,67.105140;27.750515,9.744845;28.100882,-8.525148;28.479501,-28.268318;29.219582,-66.859987;28.719241,-66.846999;27.984388,-28.527920;27.514082,-4.003703;27.247632,9.890401;26.150892,67.080144;25.738609,88.578720;25.238695,88.569424;25.651279,67.055148;26.744748,10.035956;26.927281,0.517742;27.489274,-28.787522;28.218900,-66.834010;27.718559,-66.821021;26.994161,-29.047123;26.340480,5.039187;26.241865,10.181512;25.151666,67.030152;24.738781,88.560129;24.238868,88.550834;24.652054,67.005155;25.738982,10.327067;25.753680,9.560633;26.499047,-29.306725;27.218218,-66.808032;26.717877,-66.795043;26.003934,-29.566327;25.236098,10.472623;25.166879,14.082078;24.152441,66.980159;23.738954,88.541538;23.239040,88.532243;23.652829,66.955163;24.580078,18.603523;24.733215,10.618178;25.508820,-29.825929;26.217536,-66.782054;25.717195,-66.769065;25.013707,-30.085531;24.230332,10.763734;23.993278,23.124968;23.153216,66.930167;22.739127,88.522947;22.239213,88.513652;22.653603,66.905171;23.406477,27.646413;23.727449,10.909289;24.518593,-30.345133;25.216854,-66.756076;24.716513,-66.743087;24.023480,-30.604734;23.224565,11.054845;22.819676,32.167859;22.153991,66.880174;21.739299,88.504357;21.239386,88.495061;21.654378,66.855178;22.232876,36.689304;22.721682,11.200400;23.528366,-30.864336;24.216172,-66.730098;23.715831,-66.717110;23.033253,-31.123938;22.218799,11.345956;21.646075,41.210749;21.154766,66.830182;20.739472,88.485766;20.239558,88.476471;20.655153,66.805186;21.059274,45.732194;21.715915,11.491511;22.538140,-31.383540;23.215490,-66.704121;22.715149,-66.691132;22.043026,-31.643142;21.213032,11.637067;20.472474,50.253639;20.155541,66.780189;19.739645,88.467175;19.239731,88.457880;19.655928,66.755193;19.885673,54.775085;20.710149,11.782623;21.547913,-31.902744;22.214808,-66.678143;21.714467,-66.665154;21.052799,-32.162345;20.207266,11.928178;19.298873,59.296530;19.156315,66.730197;18.739817,88.448585;18.239904,88.439289;18.656703,66.705201;18.712072,63.817975;19.704382,12.073734;20.557686,-32.421947;21.214126,-66.652165;20.713785,-66.639176;20.062572,-32.681549;19.201499,12.219289;18.157090,66.680205;18.125271,68.339420;17.739990,88.429994;17.240076,88.420698;17.538471,72.860865;17.657478,66.655208;18.698616,12.364845;19.567459,-32.941151;20.213444,-66.626187;19.713103,-66.613198;19.072345,-33.200753;18.195732,12.510400;17.157865,66.630212;16.951670,77.382311;16.740163,88.411403;16.240249,88.402108;16.364869,81.903756;16.658253,66.605216;17.692849,12.655956;18.577232,-33.460355;19.212762,-66.600209;18.712421,-66.587221;18.082118,-33.719956;17.189966,12.801511;16.158640,66.580220;15.778069,86.425201;15.740335,88.392812;15.523233,88.388776;15.240422,88.383517;15.659027,66.555224;16.687083,12.947067;17.587005,-33.979558;18.212080,-66.574232;17.711739,-66.561243;17.091891,-34.239160;16.184199,13.092622;15.159415,66.530227;14.740508,88.374222;14.240594,88.364926;14.659802,66.505231;15.681316,13.238178;16.596778,-34.498762;17.211398,-66.548254;16.711057,-66.535265;16.101664,-34.758364;15.178433,13.383733;14.160190,66.480235;13.740681,88.355631;13.240767,88.346336;13.660577,66.455239;14.675549,13.529289;15.606551,-35.017965;16.210716,-66.522276;15.710375,-66.509287;15.111437,-35.277567;14.172666,13.674845;13.160965,66.430242;12.740853,88.337040;12.240940,88.327745;12.661352,66.405246;13.669783,13.820400;14.616324,-35.537169;15.210034,-66.496298;14.709692,-66.483309;14.121210,-35.796771;13.166900,13.965956;12.161739,66.380250;11.741026,88.318450;11.241112,88.309154;11.662127,66.355254;12.664016,14.111511;13.626097,-36.056373;14.209351,-66.470320;13.709010,-66.457332;13.130983,-36.315975;12.161133,14.257067;11.162514,66.330258;10.741198,88.299859;10.241285,88.290563;10.662902,66.305261;11.658250,14.402622;12.635870,-36.575576;13.208669,-66.444343;12.708328,-66.431354;12.140756,-36.835178;11.155366,14.548178;10.163289,66.280265;9.741371,88.281268;9.241457,88.271973;9.663677,66.255269;10.652483,14.693733;11.645643,-37.094780;12.207987,-66.418365;11.707646,-66.405376;11.150529,-37.354382;10.149600,14.839289;9.164064,66.230273;8.741544,88.262677;8.241630,88.253382;8.664451,66.205276;9.646717,14.984844;10.655416,-37.613984;11.207305,-66.392387;10.706964,-66.379398;10.160302,-37.873586;9.143833,15.130400;8.164839,66.180280;7.741716,88.244087;7.241803,88.234791;7.665226,66.155284;8.640950,15.275955;9.665189,-38.133187;10.206623,-66.366409;9.706282,-66.353420;9.170075,-38.392789;8.138067,15.421511;7.165614,66.130288;6.741889,88.225496;6.241975,88.216201;6.666001,66.105292;7.635184,15.567067;8.674962,-38.652391;9.205941,-66.340431;8.705600,-66.327443;8.179848,-38.911993;7.132300,15.712622;6.166389,66.080295;5.742062,88.206905;5.242148,88.197610;5.666776,66.055299;6.629417,15.858178;7.684735,-39.171595;8.205259,-66.314454;7.704918,-66.301465;7.189621,-39.431197;6.126534,16.003733;5.167163,66.030303;4.742234,88.188314;4.242321,88.179019;4.667551,66.005307;5.623650,16.149289;6.694508,-39.690798;7.204577,-66.288476;6.704236,-66.275487;6.199394,-39.950400;5.120767,16.294844;4.167938,65.980310;3.757615,87.376701;3.410574,79.395808;3.668326,65.955314;4.617884,16.440400;5.704281,-40.210002;6.203895,-66.262498;5.703554,-66.249509;5.209167,-40.469604;4.115001,16.585955;3.168713,65.930318;3.063534,71.414916;2.824293,65.913086;2.716493,63.434023;3.612117,16.731511;4.714054,-40.729206;5.203213,-66.236520;4.702872,-66.223531;4.218940,-40.988808;3.109234,16.877066;2.369452,55.453131;2.022412,47.472238;2.606351,17.022622;3.723827,-41.248409;4.202531,-66.210542;3.702190,-66.197554;3.228713,-41.508011;2.103467,17.168177;1.675371,39.491345;1.328331,31.510453;1.600584,17.313733;2.733600,-41.767613;3.201849,-66.184565;2.701508,-66.171576;2.238486,-42.027215;1.097701,17.459289;0.981290,23.529560;0.722058,17.568015;0.634249,15.548668;1.743373,-42.286817;2.201167,-66.158587;1.700826,-66.145598;1.248259,-42.546419;0.287209,7.567775;-0.059832,-0.413117;0.753146,-42.806020;1.200485,-66.132609;0.700144,-66.119620;0.258032,-43.065622;-0.406873,-8.394010;-0.753913,-16.374902;-0.237081,-43.325224;0.199803,-66.106631;-0.300538,-66.093642;-0.732195,-43.584826;-1.100954,-24.355795;-1.447995,-32.336687;-1.227308,-43.844428;-0.800879,-66.080653;-1.301220,-66.067665;-1.722422,-44.104030;-1.795035,-40.317580;-1.965221,-44.231336;-2.142076,-48.298472;-1.801561,-66.054676;-2.301902,-66.041687;-2.489116,-56.279365
+LAND1.mowingWidth=0.50
+LAND1.obstacleCoordinates=(25.17,9.94;17.74,67.19;113.88,72.00;120.00,19.12;74.99,-4.48)
+LAND1.plannedPath=136.940221,-67.425155;136.061516,-21.604907;135.117045,27.644725;134.257061,72.488826;133.930254,89.530244;111.366178,89.110689;15.660494,87.331145;4.807861,87.129352;3.887608,65.966285;1.769872,17.264734;-0.879464,-43.662043;-1.807069,-64.994176;35.555406,-65.964109;43.773311,-66.177447;48.798326,-17.614591;49.223902,-13.501734;56.146237,-13.761876;98.648661,-15.359117;99.857663,-69.194695;129.523616,-67.779067;136.940221,-67.425155;136.690404,-67.437076;135.810075,-21.532129;134.869489,27.514924;134.007254,72.476328;133.680297,89.525597;133.180383,89.516301;133.507642,72.451332;134.374375,27.255322;135.307191,-21.386574;136.190769,-67.460918;135.691134,-67.484760;134.804308,-21.241018;133.879262,26.995720;133.008029,72.426335;132.680469,89.507006;132.180556,89.497710;132.508416,72.401339;133.384148,26.736118;134.301425,-21.095463;135.191500,-67.508602;134.691865,-67.532444;133.798541,-20.949907;132.889035,26.476516;132.008804,72.376343;131.680642,89.488415;131.180728,89.479120;131.509191,72.351347;132.393921,26.216914;133.295658,-20.804351;134.192230,-67.556286;133.692595,-67.580128;132.792775,-20.658796;131.898808,25.957313;131.009579,72.326351;130.680815,89.469824;130.180901,89.460529;130.509966,72.301354;131.403694,25.697711;132.289892,-20.513240;133.192961,-67.603970;132.693326,-67.627812;131.787008,-20.367685;130.908581,25.438109;130.010354,72.276358;129.680987,89.451234;129.181074,89.441938;129.510741,72.251362;130.413467,25.178507;131.284125,-20.222129;132.193691,-67.651654;131.694057,-67.675496;130.781242,-20.076574;129.918354,24.918905;129.011128,72.226366;128.681160,89.432643;128.181246,89.423348;128.511516,72.201369;129.423240,24.659303;130.278359,-19.931018;131.194422,-67.699338;130.694787,-67.723180;129.775475,-19.785463;128.928127,24.399702;128.011903,72.176373;127.681333,89.414052;127.181419,89.404757;127.512291,72.151377;128.433013,24.140100;129.272592,-19.639907;130.195152,-67.747022;129.695518,-67.770864;128.769709,-19.494352;127.937900,23.880498;127.012678,72.126381;126.681505,89.395462;126.181592,89.386166;126.513066,72.101385;127.442786,23.620896;128.266825,-19.348796;129.130432,-64.381752;129.195883,-67.794706;128.696248,-67.818548;128.531016,-59.202485;127.763942,-19.203241;126.947673,23.361294;126.013453,72.076388;125.681678,89.376871;125.181764,89.367575;125.513840,72.051392;126.452559,23.101693;127.261059,-19.057685;127.931600,-54.023219;128.196614,-67.842390;127.696979,-67.866232;127.332185,-48.843953;126.758176,-18.912129;125.957446,22.842091;125.014228,72.026396;124.681851,89.358280;124.181937,89.348985;124.514615,72.001400;125.462332,22.582489;126.255292,-18.766574;126.732769,-43.664687;127.197344,-67.890074;126.697709,-67.913916;126.133353,-38.485420;125.752409,-18.621018;124.967219,22.322887;124.015003,71.976403;123.682023,89.339689;123.182110,89.330394;123.515390,71.951407;124.472105,22.063285;125.249526,-18.475463;125.533937,-33.306154;126.198075,-67.937758;125.698440,-67.961600;124.934521,-28.126888;124.746642,-18.329907;123.976992,21.803683;123.015778,71.926411;122.682196,89.321099;122.182282,89.311803;122.516165,71.901415;123.481878,21.544082;124.243759,-18.184352;124.335105,-22.947622;125.198805,-67.985442;124.699171,-68.009284;123.740876,-18.038796;123.735690,-17.768356;122.986765,21.284480;122.016552,71.876419;121.682369,89.302508;121.182455,89.293213;121.516940,71.851422;122.491651,21.024878;123.136274,-12.589089;123.237993,-17.893241;124.199536,-68.033126;123.699901,-68.056968;122.735109,-17.747685;122.536858,-7.409823;121.996538,20.765276;121.017327,71.826426;120.682541,89.283917;120.182628,89.274622;120.517715,71.801430;121.501424,20.505674;121.937442,-2.230557;122.232226,-17.602130;123.200267,-68.080811;122.700632,-68.104653;121.729343,-17.456574;121.338026,2.948709;121.006311,20.246072;120.018102,71.776434;119.682714,89.265327;119.182800,89.256031;119.518490,71.751438;120.511197,19.986471;120.738610,8.127976;121.226459,-17.311019;122.200997,-68.128495;121.701362,-68.152337;120.723576,-17.165463;120.139195,13.307242;120.016084,19.726869;119.018877,71.726441;118.682887,89.246736;118.182973,89.237440;118.519264,71.701445;119.520970,19.467267;119.539779,18.486508;120.220693,-17.019907;121.201728,-68.176179;120.702093,-68.200021;119.717810,-16.874352;119.025857,19.207665;118.940363,23.665774;118.019652,71.676449;117.683059,89.228145;117.183145,89.218850;117.520039,71.651453;118.340947,28.845041;118.530743,18.948063;119.214926,-16.728796;120.202458,-68.223863;119.702824,-68.247705;118.712043,-16.583241;118.035630,18.688461;117.741531,34.024307;117.020427,71.626456;116.683232,89.209554;116.183318,89.200259;116.520814,71.601460;117.142115,39.203573;117.540516,18.428860;118.209160,-16.437685;119.203189,-68.271547;118.703554,-68.295389;117.706276,-16.292130;117.045403,18.169258;116.542700,44.382839;116.021202,71.576464;115.683404,89.190964;115.183491,89.181668;115.521589,71.551468;115.943284,49.562106;116.550290,17.909656;117.203393,-16.146574;118.203919,-68.319231;117.704285,-68.343073;116.700510,-16.001019;116.055176,17.650054;115.343868,54.741372;115.021976,71.526472;114.683577,89.172373;114.183663,89.163078;114.522364,71.501475;114.744452,59.920638;115.560063,17.390452;116.197627,-15.855463;117.204650,-68.366915;116.705015,-68.390757;115.694743,-15.709908;115.064949,17.130850;114.145036,65.099904;114.022751,71.476479;113.683750,89.153782;113.183836,89.144487;113.523139,71.451483;113.545620,70.279171;114.569836,16.871249;115.191860,-15.564352;116.205381,-68.414599;115.705746,-68.438441;114.688977,-15.418797;114.074722,16.611647;113.023526,71.426487;112.946204,75.458437;112.683922,89.135191;112.184009,89.125896;112.346789,80.637703;112.523913,71.401490;113.579609,16.352045;114.186093,-15.273241;115.206111,-68.462283;114.706476,-68.486125;113.683210,-15.127685;113.084495,16.092443;112.024301,71.376494;111.747373,85.816969;111.684095,89.116601;111.366178,89.110689;111.184181,89.107305;111.524688,71.351498;112.589382,15.832841;113.180327,-14.982130;114.206842,-68.509967;113.707207,-68.533809;112.677444,-14.836574;112.094268,15.573239;111.025076,71.326502;110.684268,89.098010;110.184354,89.088715;110.525463,71.301506;111.599155,15.313638;112.174560,-14.691019;113.207572,-68.557651;112.707938,-68.581493;111.671677,-14.545463;111.104041,15.054036;110.025851,71.276509;109.684440,89.079419;109.184527,89.070124;109.526238,71.251513;110.608928,14.794434;111.168794,-14.399908;112.208303,-68.605335;111.708668,-68.629177;110.665910,-14.254352;110.113814,14.534832;109.026625,71.226517;108.684613,89.060829;108.184699,89.051533;108.527013,71.201521;109.618701,14.275230;110.163027,-14.108797;111.209034,-68.653019;110.709399,-68.676861;109.660144,-13.963241;109.123587,14.015628;108.027400,71.176524;107.684786,89.042238;107.184872,89.032943;107.527788,71.151528;108.628474,13.756027;109.157261,-13.817686;110.209764,-68.700703;109.710129,-68.724545;108.654377,-13.672130;108.133360,13.496425;107.028175,71.126532;106.684958,89.023647;106.185045,89.014352;106.528563,71.101536;107.638247,13.236823;108.151494,-13.526575;109.210495,-68.748387;108.710860,-68.772229;107.648611,-13.381019;107.143133,12.977221;106.028950,71.076540;105.685131,89.005056;105.185217,88.995761;105.529337,71.051543;106.648020,12.717619;107.145728,-13.235463;108.211225,-68.796072;107.711591,-68.819914;106.642844,-13.089908;106.152906,12.458017;105.029725,71.026547;104.685304,88.986466;104.185390,88.977170;104.530112,71.001551;105.657793,12.198416;106.139961,-12.944352;107.211956,-68.843756;106.712321,-68.867598;105.637078,-12.798797;105.162679,11.938814;104.030500,70.976555;103.685476,88.967875;103.185563,88.958580;103.530887,70.951559;104.667566,11.679212;105.134194,-12.653241;106.212686,-68.891440;105.713052,-68.915282;104.631311,-12.507686;104.172452,11.419610;103.031275,70.926562;102.685649,88.949284;102.185735,88.939989;102.531662,70.901566;103.677339,11.160008;104.128428,-12.362130;105.213417,-68.939124;104.713782,-68.962966;103.625545,-12.216575;103.182225,10.900406;102.032049,70.876570;101.685822,88.930694;101.185908,88.921398;101.532437,70.851574;102.687112,10.640805;103.122661,-12.071019;104.214148,-68.986808;103.714513,-69.010650;102.619778,-11.925464;102.191998,10.381203;101.032824,70.826577;100.685994,88.912103;100.186081,88.902807;100.533212,70.801581;101.696885,10.121601;102.116895,-11.779908;103.214878,-69.034492;102.715243,-69.058334;101.614011,-11.634353;101.201771,9.861999;100.033599,70.776585;99.686167,88.893512;99.186253,88.884217;99.533987,70.751589;100.706658,9.602397;101.111128,-11.488797;102.215609,-69.082176;101.715974,-69.106018;100.608245,-11.343241;100.211544,9.342795;99.034374,70.726593;98.686340,88.874921;98.186426,88.865626;98.534761,70.701596;99.716431,9.083194;100.105362,-11.197686;101.216339,-69.129860;100.716705,-69.153702;99.602478,-11.052130;99.221317,8.823592;98.035149,70.676600;97.686512,88.856331;97.186599,88.847035;97.535536,70.651604;98.726204,8.563990;99.099595,-10.906575;100.217070,-69.177544;98.896710,-26.404472;98.596712,-10.761019;98.231090,8.304388;97.035924,70.626608;96.686685,88.837740;96.186771,88.828445;96.536311,70.601611;97.735977,8.044786;98.093828,-10.615464;98.184464,-15.341673;97.684011,-15.322866;97.590945,-10.469908;97.240863,7.785184;96.036699,70.576615;95.686858,88.819149;95.186944,88.809854;95.537086,70.551619;96.745750,7.525583;97.088062,-10.324353;97.183559,-15.304059;96.683106,-15.285252;96.585179,-10.178797;96.250636,7.265981;95.037473,70.526623;94.687030,88.800559;94.187116,88.791263;94.537861,70.501627;95.755523,7.006379;96.082295,-10.033242;96.182654,-15.266445;95.682201,-15.247638;95.579412,-9.887686;95.260409,6.746777;94.038248,70.476630;93.687203,88.781968;93.187289,88.772672;93.538636,70.451634;94.765296,6.487175;95.076529,-9.742131;95.181748,-15.228831;94.681296,-15.210024;94.573645,-9.596575;94.270182,6.227573;93.039023,70.426638;92.687375,88.763377;92.187462,88.754082;92.539410,70.401642;93.775069,5.967972;94.070762,-9.451019;94.180843,-15.191217;93.680391,-15.172410;93.567879,-9.305464;93.279955,5.708370;92.039798,70.376645;91.687548,88.744786;91.187634,88.735491;91.540185,70.351649;92.784842,5.448768;93.064996,-9.159908;93.179938,-15.153602;92.679485,-15.134795;92.562112,-9.014353;92.289728,5.189166;91.040573,70.326653;90.687721,88.726196;90.187807,88.716900;90.540960,70.301657;91.794615,4.929564;92.059229,-8.868797;92.179033,-15.115988;91.678580,-15.097181;91.556346,-8.723242;91.299501,4.669962;90.041348,70.276661;89.687893,88.707605;89.187980,88.698310;89.541735,70.251664;90.804388,4.410361;91.053462,-8.577686;91.178128,-15.078374;90.677675,-15.059567;90.550579,-8.432131;90.309274,4.150759;89.042122,70.226668;88.688066,88.689014;88.188152,88.679719;88.542510,70.201672;89.814161,3.891157;90.047696,-8.286575;90.177222,-15.040760;89.676770,-15.021953;89.544813,-8.141020;89.319047,3.631555;88.042897,70.176676;87.688239,88.670423;87.188325,88.661128;87.543285,70.151680;88.823934,3.371953;89.041929,-7.995464;89.176317,-15.003146;88.675865,-14.984339;88.539046,-7.849909;88.328820,3.112351;87.043672,70.126683;86.688411,88.651833;86.188498,88.642537;86.544060,70.101687;87.833707,2.852750;88.036163,-7.704353;88.175412,-14.965532;87.674959,-14.946725;87.533279,-7.558797;87.338593,2.593148;86.044447,70.076691;85.688584,88.633242;85.188670,88.623947;85.544834,70.051695;86.843480,2.333546;87.030396,-7.413242;87.174507,-14.927918;86.674054,-14.909111;86.527513,-7.267686;86.348366,2.073944;85.045222,70.026698;84.688757,88.614651;84.188843,88.605356;84.545609,70.001702;85.853253,1.814342;86.024630,-7.122131;86.173602,-14.890304;85.673149,-14.871497;85.521746,-6.976575;85.358139,1.554741;84.045997,69.976706;83.688929,88.596061;83.189016,88.586765;83.546384,69.951710;84.863026,1.295139;85.018863,-6.831020;85.172696,-14.852690;84.672244,-14.833883;84.515980,-6.685464;84.367912,1.035537;83.046772,69.926714;82.689102,88.577470;82.189188,88.568175;82.547159,69.901717;83.872799,0.775935;84.013096,-6.539909;84.171791,-14.815076;83.671339,-14.796269;83.510213,-6.394353;83.377685,0.516333;82.047546,69.876721;81.689275,88.558879;81.189361,88.549584;81.547934,69.851725;82.882572,0.256731;83.007330,-6.248798;83.170886,-14.777462;82.670433,-14.758655;82.504447,-6.103242;82.387459,-0.002870;81.048321,69.826729;80.689447,88.540288;80.189534,88.530993;80.548709,69.801732;81.892345,-0.262472;82.001563,-5.957687;82.169981,-14.739848;81.669528,-14.721041;81.498680,-5.812131;81.397232,-0.522074;80.049096,69.776736;79.689620,88.521698;79.189706,88.512402;79.549484,69.751740;80.902118,-0.781676;80.995797,-5.666575;81.169076,-14.702234;80.668623,-14.683427;80.492914,-5.521020;80.407005,-1.041278;79.049871,69.726744;78.689793,88.503107;78.189879,88.493812;78.550258,69.701748;79.911891,-1.300880;79.990030,-5.375464;80.168170,-14.664620;79.667718,-14.645813;79.487147,-5.229909;79.416778,-1.560481;78.050646,69.676751;77.689965,88.484516;77.190052,88.475221;77.551033,69.651755;78.921664,-1.820083;78.984264,-5.084353;79.167265,-14.627006;78.666813,-14.608199;78.481380,-4.938798;78.426551,-2.079685;77.051421,69.626759;76.690138,88.465926;76.190224,88.456630;76.551808,69.601763;77.931437,-2.339287;77.978497,-4.793242;78.166360,-14.589392;77.665907,-14.570585;77.475614,-4.647687;77.436324,-2.598889;76.052196,69.576766;75.690311,88.447335;75.190397,88.438039;75.552583,69.551770;76.941210,-2.858491;76.972731,-4.502131;77.165455,-14.551778;76.665002,-14.532971;76.469847,-4.356576;76.446097,-3.118092;75.052970,69.526774;74.690483,88.428744;74.190570,88.419449;74.553358,69.501778;75.950983,-3.377694;75.966964,-4.211020;76.164550,-14.514164;75.664097,-14.495357;75.464081,-4.065465;75.455870,-3.637296;74.053745,69.476782;73.690656,88.410153;73.190742,88.400858;73.554133,69.451785;74.960756,-3.896898;74.961197,-3.919909;75.163644,-14.476550;74.663192,-14.457743;74.465643,-4.156500;74.458314,-3.774353;73.054520,69.426789;72.690829,88.391563;72.190915,88.382267;72.554907,69.401793;73.955431,-3.628798;73.970529,-4.416102;74.162739,-14.438936;73.662287,-14.420129;73.475416,-4.675703;73.452548,-3.483242;72.055295,69.376797;71.691001,88.372972;71.191087,88.363677;71.555682,69.351800;72.949664,-3.337687;72.980302,-4.935305;73.161834,-14.401322;72.661381,-14.382515;72.485189,-5.194907;72.446781,-3.192131;71.056070,69.326804;70.691174,88.354381;70.191260,88.345086;70.556457,69.301808;71.943898,-3.046576;71.990075,-5.454509;72.160929,-14.363708;71.660476,-14.344901;71.494962,-5.714111;71.441014,-2.901020;70.056845,69.276812;69.691346,88.335791;69.191433,88.326495;69.557232,69.251816;70.938131,-2.755465;70.999848,-5.973713;71.160024,-14.326094;70.659571,-14.307287;70.504735,-6.233314;70.435248,-2.609909;69.057619,69.226819;68.691519,88.317200;68.191605,88.307904;68.558007,69.201823;69.932365,-2.464354;70.009621,-6.492916;70.159118,-14.288480;69.658666,-14.269673;69.514508,-6.752518;69.429481,-2.318798;68.058394,69.176827;67.691692,88.298609;67.191778,88.289314;67.558782,69.151831;68.926598,-2.173243;69.019394,-7.012120;69.158213,-14.250866;68.657761,-14.232059;68.524281,-7.271722;68.423715,-2.027687;67.059169,69.126835;66.691864,88.280018;66.191951,88.270723;66.559557,69.101838;67.920831,-1.882131;68.029167,-7.531324;68.157308,-14.213252;67.656855,-14.194445;67.534054,-7.790925;67.417948,-1.736576;66.059944,69.076842;65.692037,88.261428;65.192123,88.252132;65.560331,69.051846;66.915065,-1.591020;67.038940,-8.050527;67.156403,-14.175638;66.655950,-14.156831;66.543827,-8.310129;66.412182,-1.445465;65.060719,69.026850;64.692210,88.242837;64.192296,88.233542;64.561106,69.001853;65.909298,-1.299909;66.048713,-8.569731;66.155498,-14.138024;65.655045,-14.119217;65.553600,-8.829333;65.406415,-1.154354;64.061494,68.976857;63.692382,88.224246;63.192469,88.214951;63.561881,68.951861;64.903532,-1.008798;65.058486,-9.088935;65.154592,-14.100410;64.654140,-14.081603;64.563373,-9.348536;64.400648,-0.863243;63.062269,68.926865;62.692555,88.205655;62.192641,88.196360;62.562656,68.901869;63.897765,-0.717687;64.068259,-9.608138;64.153687,-14.062796;63.653235,-14.043989;63.573146,-9.867740;63.394882,-0.572132;62.063043,68.876872;61.692728,88.187065;61.192814,88.177769;61.563431,68.851876;62.891999,-0.426576;63.078032,-10.127342;63.152782,-14.025182;62.652329,-14.006375;62.582919,-10.386944;62.389115,-0.281021;61.063818,68.826880;60.692900,88.168474;60.192987,88.159179;60.564206,68.801884;61.886232,-0.135465;62.087805,-10.646546;62.151877,-13.987568;61.651424,-13.968761;61.592692,-10.906147;61.383349,0.010091;60.064593,68.776887;59.693073,88.149883;59.193159,88.140588;59.564981,68.751891;60.880465,0.155646;61.097578,-11.165749;61.150972,-13.949954;60.650519,-13.931147;60.602465,-11.425351;60.377582,0.301202;59.065368,68.726895;58.693246,88.131293;58.193332,88.121997;58.565755,68.701899;59.874699,0.446757;60.107351,-11.684953;60.150066,-13.912340;59.649614,-13.893532;59.612238,-11.944555;59.371816,0.592313;58.066143,68.676903;57.693418,88.112702;57.193505,88.103407;57.566530,68.651906;58.868932,0.737868;59.117124,-12.204157;59.149161,-13.874725;58.648709,-13.855918;58.622011,-12.463758;58.366049,0.883424;57.066918,68.626910;56.693591,88.094111;56.193677,88.084816;56.567305,68.601914;57.863166,1.028979;58.126897,-12.723360;58.148256,-13.837111;57.647803,-13.818304;57.631784,-12.982962;57.360283,1.174535;56.067693,68.576918;55.693764,88.075520;55.193850,88.066225;55.568080,68.551921;56.857399,1.320090;57.136670,-13.242564;57.147351,-13.799497;56.646898,-13.780690;56.641557,-13.502166;56.354516,1.465646;55.068467,68.526925;54.693936,88.056930;54.194023,88.047634;54.568855,68.501929;55.851633,1.611202;56.146443,-13.761768;56.146446,-13.761883;56.146237,-13.761876;55.645993,-13.743076;55.348749,1.756757;54.069242,68.476933;53.694109,88.038339;53.194195,88.029044;53.569630,68.451937;54.845866,1.902313;55.145540,-13.724269;54.645088,-13.705462;54.342983,2.047868;53.070017,68.426940;52.694282,88.019748;52.194368,88.010453;52.570404,68.401944;53.840100,2.193424;54.144635,-13.686655;53.644183,-13.667848;53.337216,2.338979;52.070792,68.376948;51.694454,88.001158;51.194541,87.991862;51.571179,68.351952;52.834333,2.484535;53.143730,-13.649041;52.643277,-13.630234;52.331450,2.630090;51.071567,68.326956;50.694627,87.982567;50.194713,87.973271;50.571954,68.301959;51.828566,2.775646;52.142825,-13.611427;51.642372,-13.592620;51.325683,2.921201;50.072342,68.276963;49.694800,87.963976;49.194886,87.954681;49.572729,68.251967;50.822800,3.066757;51.141920,-13.573813;50.641467,-13.555006;50.319917,3.212312;49.073116,68.226971;48.694972,87.945385;48.195059,87.936090;48.573504,68.201974;49.817033,3.357868;50.141014,-13.536199;49.640562,-13.517392;49.314150,3.503424;48.073891,68.176978;47.695145,87.926795;47.195231,87.917499;47.574279,68.151982;48.811267,3.648979;49.153262,-14.184416;48.798326,-17.614591;48.731362,-18.261751;48.719741,-17.655795;48.308383,3.794535;47.074666,68.126986;46.695317,87.908204;46.195404,87.898909;46.575054,68.101990;47.805500,3.940090;48.224628,-17.915397;48.309462,-22.339085;47.887562,-26.416420;47.729514,-18.174999;47.302617,4.085646;46.075441,68.076993;45.695490,87.889613;45.195576,87.880318;45.575828,68.051997;46.799734,4.231201;47.234401,-18.434601;47.465662,-30.493755;47.043762,-34.571089;46.739287,-18.694202;46.296850,4.376757;45.076216,68.027001;44.695663,87.871023;44.195749,87.861727;44.576603,68.002005;45.793967,4.522312;46.244174,-18.953804;46.621861,-38.648424;46.199961,-42.725758;45.749060,-19.213406;45.291084,4.667868;44.076991,67.977008;43.695835,87.852432;43.195922,87.843136;43.577378,67.952012;44.788200,4.813423;45.253947,-19.473008;45.778061,-46.803093;45.356161,-50.880428;44.758833,-19.732610;44.285317,4.958979;43.077766,67.927016;42.696008,87.833841;42.196094,87.824546;42.578153,67.902020;43.782434,5.104534;44.263720,-19.992211;44.934261,-54.957762;44.512361,-59.035097;43.768606,-20.251813;43.279551,5.250090;42.078540,67.877024;41.696181,87.815250;41.196267,87.805955;41.578928,67.852027;42.776667,5.395646;43.273493,-20.511415;44.090461,-63.112431;43.649086,-66.174222;42.778379,-20.771017;42.273784,5.541201;41.079315,67.827031;40.696353,87.796660;40.196440,87.787364;40.579703,67.802035;41.770901,5.686757;42.283266,-21.030619;43.148745,-66.161233;42.648404,-66.148244;41.788152,-21.290221;41.268017,5.832312;40.080090,67.777039;39.696526,87.778069;39.196612,87.768774;39.580478,67.752042;40.765134,5.977868;41.293039,-21.549822;42.148063,-66.135255;41.647722,-66.122266;40.797925,-21.809424;40.262251,6.123423;39.080865,67.727046;38.696699,87.759478;38.196785,87.750183;38.581252,67.702050;39.759368,6.268979;40.302812,-22.069026;41.147381,-66.109277;40.647040,-66.096288;39.807698,-22.328628;39.256484,6.414534;38.081640,67.677054;37.696871,87.740887;37.196958,87.731592;37.582027,67.652058;38.753601,6.560090;39.312585,-22.588230;40.146699,-66.083299;39.646358,-66.070310;38.817471,-22.847832;38.250718,6.705645;37.082415,67.627061;36.697044,87.722297;36.197130,87.713001;36.582802,67.602065;37.747834,6.851201;38.322358,-23.107433;39.146017,-66.057322;38.645676,-66.044333;37.827244,-23.367035;37.244951,6.996756;36.083190,67.577069;35.697217,87.703706;35.197303,87.694411;35.583577,67.552073;36.742068,7.142312;37.332131,-23.626637;38.145335,-66.031344;37.644994,-66.018355;36.837017,-23.886239;36.239185,7.287868;35.083964,67.527077;34.697389,87.685115;34.197476,87.675820;34.584352,67.502080;35.736301,7.433423;36.341904,-24.145841;37.144653,-66.005366;36.644312,-65.992377;35.846790,-24.405443;35.233418,7.578979;34.084739,67.477084;33.697562,87.666525;33.197648,87.657229;33.585127,67.452088;34.730535,7.724534;35.351677,-24.665044;36.143971,-65.979388;35.643630,-65.966399;34.856563,-24.924646;34.227651,7.870090;33.085514,67.427092;32.697735,87.647934;32.197821,87.638639;32.585901,67.402095;33.724768,8.015645;34.361450,-25.184248;35.072074,-62.239917;35.143289,-65.953410;34.642948,-65.940421;34.485274,-57.718472;33.866336,-25.443850;33.221885,8.161201;32.086289,67.377099;31.697907,87.629343;31.197994,87.620048;31.586676,67.352103;32.719002,8.306756;33.371223,-25.703452;33.898473,-53.197027;34.142607,-65.927433;33.642266,-65.914444;33.311672,-48.675582;32.876109,-25.963054;32.216118,8.452312;31.087064,67.327107;30.698080,87.610752;30.198166,87.601457;30.587451,67.302111;31.713235,8.597867;32.380996,-26.222655;32.724872,-44.154136;33.141925,-65.901455;32.641584,-65.888466;32.138071,-39.632691;31.885882,-26.482257;31.210352,8.743423;30.087839,67.277114;29.698253,87.592162;29.198339,87.582866;29.588226,67.252118;30.707469,8.888978;31.390769,-26.741859;31.551270,-35.111246;32.141243,-65.875477;31.640902,-65.862488;30.964470,-30.589801;30.895655,-27.001461;30.204585,9.034534;29.088613,67.227122;28.698425,87.573571;28.198512,87.564276;28.589001,67.202126;29.701702,9.180090;30.377669,-26.068356;30.400542,-27.261063;31.140561,-65.849499;30.640219,-65.836510;29.905428,-27.520665;29.790868,-21.546910;29.198819,9.325645;28.089388,67.177129;27.698598,87.554980;27.198684,87.545685;27.589776,67.152133;28.695935,9.471201;29.204068,-17.025465;29.410315,-27.780266;30.139878,-65.823521;29.639537,-65.810532;28.915201,-28.039868;28.617267,-12.504020;28.193052,9.616756;27.090163,67.127137;26.698771,87.536390;26.198857,87.527094;26.590551,67.102141;27.690169,9.762312;28.030466,-7.982575;28.420088,-28.299470;29.139196,-65.797544;28.638855,-65.784555;27.924974,-28.559072;27.443666,-3.461130;27.187286,9.907867;26.090938,67.077145;25.698943,87.517799;25.199030,87.508503;25.591325,67.052148;26.684402,10.053423;26.856865,1.060316;27.429861,-28.818674;28.138514,-65.771566;27.638173,-65.758577;26.934747,-29.078276;26.270064,5.581761;26.181519,10.198978;25.091713,67.027152;24.699116,87.499208;24.199202,87.489913;24.592100,67.002156;25.678636,10.344534;25.683264,10.103206;26.439634,-29.337877;27.137832,-65.745588;26.637491,-65.732599;25.944520,-29.597479;25.175752,10.490089;25.096463,14.624651;24.092488,66.977160;23.699288,87.480617;23.199375,87.471322;23.592875,66.952163;24.509662,19.146096;24.672869,10.635645;25.449407,-29.857081;26.137150,-65.719610;25.636809,-65.706621;24.954293,-30.116683;24.169986,10.781200;23.922862,23.667542;23.093263,66.927167;22.699461,87.462027;22.199547,87.452731;22.593650,66.902171;23.336061,28.188987;23.667103,10.926756;24.459180,-30.376285;25.136468,-65.693632;24.636127,-65.680643;23.964066,-30.635887;23.164219,11.072312;22.749260,32.710432;22.094037,66.877175;21.699634,87.443436;21.199720,87.434141;21.594425,66.852179;22.162460,37.231877;22.661336,11.217867;23.468953,-30.895488;24.135786,-65.667655;23.635445,-65.654666;22.973839,-31.155090;22.158453,11.363423;21.575659,41.753322;21.094812,66.827182;20.699806,87.424845;20.199893,87.415550;20.595200,66.802186;20.988858,46.274768;21.655569,11.508978;22.478726,-31.414692;23.135104,-65.641677;22.634763,-65.628688;21.983612,-31.674294;21.152686,11.654534;20.402058,50.796213;20.095587,66.777190;19.699979,87.406255;19.200065,87.396959;19.595975,66.752194;19.815257,55.317658;20.649803,11.800089;21.488499,-31.933896;22.134422,-65.615699;21.634081,-65.602710;20.993385,-32.193498;20.146920,11.945645;19.228456,59.839103;19.096362,66.727198;18.700152,87.387664;18.200238,87.378368;18.596749,66.702201;18.641656,64.360548;19.644036,12.091200;20.498272,-32.453099;21.133740,-65.589721;20.633399,-65.576732;20.003158,-32.712701;19.141153,12.236756;18.097137,66.677205;18.054855,68.881994;17.700324,87.369073;17.200411,87.359778;17.468054,73.403439;17.597524,66.652209;18.638270,12.382311;19.508045,-32.972303;20.133058,-65.563743;19.632717,-65.550754;19.012931,-33.231905;18.135386,12.527867;17.097912,66.627213;16.881254,77.924884;16.700497,87.350482;16.200583,87.341187;16.294453,82.446329;16.598299,66.602216;17.632503,12.673422;18.517818,-33.491507;19.132376,-65.537766;18.632035,-65.524777;18.022704,-33.751109;17.129620,12.818978;16.098687,66.577220;15.707652,86.967774;15.700670,87.331892;15.660494,87.331145;15.200756,87.322596;15.599074,66.552224;16.626737,12.964534;17.527591,-34.010710;18.131694,-65.511788;17.631353,-65.498799;17.032477,-34.270312;16.123853,13.110089;15.099461,66.527228;14.700842,87.313301;14.200929,87.304006;14.599849,66.502232;15.620970,13.255645;16.537364,-34.529914;17.131012,-65.485810;16.630671,-65.472821;16.042250,-34.789516;15.118087,13.401200;14.100236,66.477235;13.701015,87.294710;13.201101,87.285415;13.600624,66.452239;14.615203,13.546756;15.547137,-35.049118;16.130330,-65.459832;15.629989,-65.446843;15.052023,-35.308720;14.112320,13.692311;13.101011,66.427243;12.701188,87.276119;12.201274,87.266824;12.601398,66.402247;13.609437,13.837867;14.556910,-35.568321;15.129648,-65.433854;14.629307,-65.420865;14.061797,-35.827923;13.106554,13.983422;12.101786,66.377250;11.701360,87.257529;11.201447,87.248233;11.602173,66.352254;12.603670,14.128978;13.566683,-36.087525;14.128966,-65.407877;13.628625,-65.394888;13.071570,-36.347127;12.100787,14.274533;11.102561,66.327258;10.701533,87.238938;10.201619,87.229643;10.602948,66.302262;11.597904,14.420089;12.576456,-36.606729;13.128284,-65.381899;12.627943,-65.368910;12.081343,-36.866331;11.095020,14.565644;10.103336,66.277266;9.701706,87.220347;9.201792,87.211052;9.603723,66.252269;10.592137,14.711200;11.586229,-37.125932;12.127602,-65.355921;11.627261,-65.342932;11.091116,-37.385534;10.089254,14.856756;9.104110,66.227273;8.701878,87.201757;8.201965,87.192461;8.604498,66.202277;9.586371,15.002311;10.596002,-37.645136;11.126920,-65.329943;10.626579,-65.316954;10.100889,-37.904738;9.083487,15.147867;8.104885,66.177281;7.702051,87.183166;7.202137,87.173871;7.605273,66.152284;8.580604,15.293422;9.605775,-38.164340;10.126238,-65.303965;9.625896,-65.290976;9.110662,-38.423942;8.077721,15.438978;7.105660,66.127288;6.702224,87.164575;6.202310,87.155280;6.606048,66.102292;7.574838,15.584533;8.615548,-38.683543;9.125555,-65.277988;8.625214,-65.264999;8.120435,-38.943145;7.071954,15.730089;6.106435,66.077296;5.702396,87.145984;5.202483,87.136689;5.606822,66.052300;6.569071,15.875644;7.625321,-39.202747;8.124873,-65.252010;7.624532,-65.239021;7.130208,-39.462349;6.066188,16.021200;5.107210,66.027303;4.734767,85.448411;4.387726,77.467519;4.607597,66.002307;5.563304,16.166755;6.635094,-39.721951;7.124191,-65.226032;6.623850,-65.213043;6.139981,-39.981553;5.060421,16.312311;4.107985,65.977311;4.040686,69.486626;3.887608,65.966285;3.693645,61.505734;4.557538,16.457866;5.644867,-40.241154;6.123509,-65.200054;5.623168,-65.187065;5.149754,-40.500756;4.054655,16.603422;3.346605,53.524841;2.999564,45.543949;3.551771,16.748978;4.654640,-40.760358;5.122827,-65.174076;4.622486,-65.161087;4.159527,-41.019960;3.048888,16.894533;2.652523,37.563056;2.305483,29.582163;2.546005,17.040089;3.664413,-41.279562;4.122145,-65.148099;3.621804,-65.135110;3.169300,-41.539163;2.043121,17.185644;1.958442,21.601271;1.769872,17.264734;1.611401,13.620378;2.674186,-41.798765;3.121463,-65.122121;2.621122,-65.109132;2.179073,-42.058367;1.264361,5.639486;0.917320,-2.341407;1.683959,-42.317969;2.120781,-65.096143;1.620440,-65.083154;1.188846,-42.577571;0.570279,-10.322299;0.223239,-18.303192;0.693732,-42.837173;1.120099,-65.070165;0.619758,-65.057176;0.198619,-43.096774;-0.123802,-26.284084;-0.470843,-34.264977;-0.296495,-43.356376;0.119417,-65.044187;-0.380924,-65.031198;-0.791608,-43.615978;-0.817883,-42.245869;-0.879464,-43.662043;-1.164924,-50.226762;-0.881265,-65.018210;-1.381606,-65.005221;-1.511964,-58.207655
LAND1.returnPathCoordinates=-1
LAND1.returnPathRawCoordinates=-1
LAND1.returnPointCoordinates=-1
-LAND1.updateTime=2025-12-26 15\:36\:20
+LAND1.updateTime=2025-12-26 16\:29\:20
LAND1.userId=-1
diff --git a/set.properties b/set.properties
index 32eb2d1..b53e384 100644
--- a/set.properties
+++ b/set.properties
@@ -1,5 +1,5 @@
#Mower Configuration Properties - Updated
-#Fri Dec 26 15:55:52 CST 2025
+#Fri Dec 26 17:35:17 CST 2025
appVersion=-1
boundaryLengthVisible=false
currentWorkLandNumber=LAND1
@@ -8,12 +8,12 @@
handheldMarkerId=1872
idleTrailDurationSeconds=60
manualBoundaryDrawingMode=false
-mapScale=50.00
+mapScale=1.32
measurementModeEnabled=false
mowerId=6258
serialAutoConnect=true
serialBaudRate=115200
serialPortName=COM15
simCardNumber=-1
-viewCenterX=-67.56
-viewCenterY=-10.16
+viewCenterX=-71.61
+viewCenterY=-56.92
diff --git a/src/denglu/Denglu.java b/src/denglu/Denglu.java
index 98117a5..469f0b5 100644
--- a/src/denglu/Denglu.java
+++ b/src/denglu/Denglu.java
@@ -9,6 +9,7 @@
import udpdell.UDPServer;
import user.Usrdell;
import Mqttmessage.Client;
+import login.LoginVerifier;
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
@@ -438,11 +439,17 @@
boolean isRemember = "1".equals(rememberPwd);
rememberMe.setSelected(isRemember);
- // 濡傛灉璁颁綇鎴戣閫変腑锛屽~鍏呭瘑鐮�
+ // 濡傛灉璁颁綇鎴戣閫変腑锛屽~鍏呭瘑鐮佸苟鑷姩鐧诲綍锛堝欢杩熸墽琛岋紝纭繚绐楀彛宸叉樉绀猴級
if (isRemember) {
String savedPassword = UserChuShiHua.getProperty("password");
- if (savedPassword != null && !savedPassword.equals("-1")) {
+ String savedEmail = UserChuShiHua.getProperty("email");
+ if (savedPassword != null && !savedPassword.equals("-1") &&
+ savedEmail != null && !savedEmail.equals("-1")) {
passwordField.setText(savedPassword);
+ // 寤惰繜鎵ц鑷姩鐧诲綍锛岀‘淇濈獥鍙e凡缁忔樉绀�
+ SwingUtilities.invokeLater(() -> {
+ performAutoLogin(savedEmail, savedPassword);
+ });
}
}
}
@@ -459,11 +466,11 @@
}
private void performLogin() {
- String username = usernameField.getText().trim();
+ String usernameOrEmail = usernameField.getText().trim();
String password = new String(passwordField.getPassword()).trim();
// 杈撳叆楠岃瘉
- if (username.isEmpty()) {
+ if (usernameOrEmail.isEmpty()) {
JOptionPane.showMessageDialog(this,
"璇疯緭鍏ョ敤鎴峰悕鎴栭偖绠�",
"杈撳叆閿欒",
@@ -481,43 +488,117 @@
return;
}
- // 楠岃瘉鐢ㄦ埛鍚嶅拰瀵嗙爜
- if (validateLogin(username, password)) {
- // 鏇存柊鏈�鍚庣櫥褰曟椂闂�
- UserChuShiHua.updateProperty("lastLoginTime", String.valueOf(System.currentTimeMillis()));
-
- // 淇濆瓨璁颁綇鎴戠姸鎬�
- if (rememberMe.isSelected()) {
- UserChuShiHua.updateProperty("rememberPassword", "1");
- UserChuShiHua.updateProperty("userName", username);
- } else {
- UserChuShiHua.updateProperty("rememberPassword", "0");
+ // 鑾峰彇閭鍦板潃锛堝鏋滆緭鍏ョ殑鏄敤鎴峰悕锛屼粠閰嶇疆鏂囦欢涓幏鍙栧搴旂殑閭锛�
+ String email = getEmailFromInput(usernameOrEmail);
+
+ // 绂佺敤鐧诲綍鎸夐挳锛岄槻姝㈤噸澶嶇偣鍑�
+ loginButton.setEnabled(false);
+
+ // 鍦ㄦ柊绾跨▼涓皟鐢ˋPI锛岄伩鍏嶉樆濉濽I
+ new Thread(() -> {
+ try {
+ // 璋冪敤鐧诲綍楠岃瘉API
+ LoginVerifier.LoginVerifyResponse response = LoginVerifier.verifyLogin(email, password);
+
+ // 鍦‥DT绾跨▼涓洿鏂癠I
+ SwingUtilities.invokeLater(() -> {
+ loginButton.setEnabled(true);
+
+ if (response.isSuccess()) {
+ // 鐧诲綍鎴愬姛
+ // 鏇存柊鏈�鍚庣櫥褰曟椂闂�
+ UserChuShiHua.updateProperty("lastLoginTime", String.valueOf(System.currentTimeMillis()));
+
+ // 淇濆瓨璁颁綇鎴戠姸鎬�
+ if (rememberMe.isSelected()) {
+ UserChuShiHua.updateProperty("rememberPassword", "1");
+ UserChuShiHua.updateProperty("userName", usernameOrEmail);
+ UserChuShiHua.updateProperty("email", email);
+ UserChuShiHua.updateProperty("password", password);
+ } else {
+ UserChuShiHua.updateProperty("rememberPassword", "0");
+ }
+
+ // 鍏抽棴鐧诲綍绐楀彛骞舵墦寮�棣栭〉
+ openMainApplication();
+ } else {
+ // 鐧诲綍澶辫触锛屾樉绀洪敊璇俊鎭�
+ String errorMessage = response.getMessage() != null ?
+ response.getMessage() : "鐢ㄦ埛鍚嶆垨瀵嗙爜閿欒锛�";
+ JOptionPane.showMessageDialog(this,
+ errorMessage,
+ "鐧诲綍澶辫触",
+ JOptionPane.ERROR_MESSAGE);
+ passwordField.setText("");
+ passwordField.requestFocus();
+ }
+ });
+ } catch (Exception e) {
+ // 寮傚父澶勭悊锛屾仮澶嶆寜閽苟鏄剧ず閿欒
+ SwingUtilities.invokeLater(() -> {
+ loginButton.setEnabled(true);
+ JOptionPane.showMessageDialog(this,
+ "鐧诲綍鏃跺彂鐢熼敊璇�: " + e.getMessage(),
+ "閿欒",
+ JOptionPane.ERROR_MESSAGE);
+ passwordField.setText("");
+ passwordField.requestFocus();
+ });
}
-
- // 鍏抽棴鐧诲綍绐楀彛骞舵墦寮�棣栭〉
- openMainApplication();
-
- } else {
- JOptionPane.showMessageDialog(this,
- "鐢ㄦ埛鍚嶆垨瀵嗙爜閿欒锛�",
- "鐧诲綍澶辫触",
- JOptionPane.ERROR_MESSAGE);
- passwordField.setText("");
- passwordField.requestFocus();
- }
+ }).start();
}
- private boolean validateLogin(String username, String password) {
- // 浠嶶serChuShiHua鑾峰彇瀛樺偍鐨勭敤鎴锋暟鎹繘琛屾瘮杈�
- String storedUsername = UserChuShiHua.getProperty("userName");
- String storedPassword = UserChuShiHua.getProperty("password");
- String storedEmail = UserChuShiHua.getProperty("email");
-
- // 妫�鏌ョ敤鎴峰悕/閭鍜屽瘑鐮佹槸鍚﹀尮閰�
- boolean usernameMatch = username.equals(storedUsername) || username.equals(storedEmail);
- boolean passwordMatch = password.equals(storedPassword);
-
- return usernameMatch && passwordMatch;
+ // 閭楠岃瘉鏂规硶
+ private boolean isValidEmail(String email) {
+ // 绠�鍗曠殑閭鏍煎紡楠岃瘉
+ String emailRegex = "^[a-zA-Z0-9_+&*-]+(?:\\.[a-zA-Z0-9_+&*-]+)*@(?:[a-zA-Z0-9-]+\\.)+[a-zA-Z]{2,7}$";
+ return email != null && email.matches(emailRegex);
+ }
+
+ // 鑾峰彇閭鍦板潃锛堝鏋滆緭鍏ョ殑鏄敤鎴峰悕锛屽垯浠庨厤缃枃浠朵腑鑾峰彇閭锛�
+ private String getEmailFromInput(String usernameOrEmail) {
+ // 濡傛灉杈撳叆鐨勬槸閭鏍煎紡锛岀洿鎺ヨ繑鍥�
+ if (isValidEmail(usernameOrEmail)) {
+ return usernameOrEmail;
+ }
+ // 鍚﹀垯锛屼粠閰嶇疆鏂囦欢涓幏鍙栦繚瀛樼殑閭
+ String savedEmail = UserChuShiHua.getProperty("email");
+ if (savedEmail != null && !savedEmail.equals("-1")) {
+ // 妫�鏌ヨ緭鍏ョ殑鐢ㄦ埛鍚嶆槸鍚﹀尮閰嶄繚瀛樼殑鐢ㄦ埛鍚�
+ String savedUsername = UserChuShiHua.getProperty("userName");
+ if (usernameOrEmail.equals(savedUsername)) {
+ return savedEmail;
+ }
+ }
+ // 濡傛灉鎵句笉鍒伴偖绠憋紝杩斿洖杈撳叆鐨勫瓧绗︿覆锛堝彲鑳芥槸閭鏍煎紡浣嗛獙璇佸け璐ワ紝鎴栬�呯敤鎴峰悕涓嶅瓨鍦級
+ return usernameOrEmail;
+ }
+
+ // 鑷姩鐧诲綍锛堜粠閰嶇疆鏂囦欢璇诲彇閭鍜屽瘑鐮侊級
+ private void performAutoLogin(String email, String password) {
+ // 鍦ㄦ柊绾跨▼涓皟鐢ˋPI锛岄伩鍏嶉樆濉濽I
+ new Thread(() -> {
+ try {
+ LoginVerifier.LoginVerifyResponse response = LoginVerifier.verifyLogin(email, password);
+
+ SwingUtilities.invokeLater(() -> {
+ if (response.isSuccess()) {
+ // 鐧诲綍鎴愬姛锛岃烦杞埌涓婚〉
+ openMainApplication();
+ } else {
+ // 鐧诲綍澶辫触锛屾竻绌哄瘑鐮佸瓧娈碉紝璁╃敤鎴烽噸鏂拌緭鍏�
+ passwordField.setText("");
+ usernameField.requestFocus();
+ }
+ });
+ } catch (Exception e) {
+ // 寮傚父澶勭悊锛屾竻绌哄瘑鐮佸瓧娈�
+ SwingUtilities.invokeLater(() -> {
+ passwordField.setText("");
+ usernameField.requestFocus();
+ });
+ }
+ }).start();
}
private void openMainApplication() {
@@ -595,17 +676,7 @@
System.out.println("鍒濆鐢ㄦ埛鍚�: " + UserChuShiHua.getProperty("userName"));
System.out.println("鍒濆瀵嗙爜: " + UserChuShiHua.getProperty("password"));
- // 妫�鏌ユ槸鍚﹁浣忓瘑鐮侊紝濡傛灉鏄垯鐩存帴杩涘叆涓婚〉
- String rememberPwd = UserChuShiHua.getProperty("rememberPassword");
- if ("1".equals(rememberPwd)) {
- String storedUser = UserChuShiHua.getProperty("userName");
- if (storedUser != null && !storedUser.equals("-1")) {
- launchMainApp();
- return;
- }
- }
-
- // 鍚姩鐧诲綍鐣岄潰
+ // 鍚姩鐧诲綍鐣岄潰锛堣嚜鍔ㄧ櫥褰曢�昏緫鍦� loadUserPreferences 涓鐞嗭級
EventQueue.invokeLater(() -> {
try {
new Denglu().setVisible(true);
diff --git a/src/denglu/RegistrationFrame.java b/src/denglu/RegistrationFrame.java
index 7e5cb96..919877d 100644
--- a/src/denglu/RegistrationFrame.java
+++ b/src/denglu/RegistrationFrame.java
@@ -1,11 +1,16 @@
package denglu;
import ui.UIConfig;
+import login.EmailCodeSender;
+import login.UserRegister;
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
import java.util.HashMap;
import java.util.Map;
+import javax.swing.event.DocumentEvent;
+import javax.swing.event.DocumentListener;
+import java.util.Arrays;
public class RegistrationFrame extends JFrame {
private JTextField userField;
@@ -17,6 +22,7 @@
private JButton cancelButton;
private JButton sendCodeButton;
private JLabel userLabel, emailLabel, verificationCodeLabel, passLabel, confirmPassLabel;
+ private JLabel passwordHintLabel, matchStatusLabel, emailHintLabel;
// 涓婚棰滆壊
private final Color THEME_COLOR = new Color(46, 139, 87);
@@ -30,7 +36,6 @@
// 楠岃瘉鐮佺浉鍏�
private Timer countdownTimer;
private int countdownSeconds = 60;
- private String generatedVerificationCode;
public RegistrationFrame(Denglu parent, String languageCode) {
this.parentFrame = parent;
@@ -225,13 +230,23 @@
emailLabel.setAlignmentX(Component.LEFT_ALIGNMENT);
emailField = new JTextField();
- emailField.setMaximumSize(new Dimension(Integer.MAX_VALUE, 35));
emailField.setFont(new Font("PingFang SC", Font.PLAIN, 14));
emailField.setBorder(BorderFactory.createCompoundBorder(
BorderFactory.createLineBorder(new Color(200, 200, 200)),
BorderFactory.createEmptyBorder(5, 8, 5, 8)
));
- emailField.setAlignmentX(Component.LEFT_ALIGNMENT);
+
+ JPanel emailContainer = new JPanel(new BorderLayout());
+ emailContainer.setBackground(Color.WHITE);
+ emailContainer.setMaximumSize(new Dimension(Integer.MAX_VALUE, 35));
+ emailContainer.setAlignmentX(Component.LEFT_ALIGNMENT);
+ emailContainer.add(emailField, BorderLayout.CENTER);
+
+ emailHintLabel = new JLabel("");
+ emailHintLabel.setFont(new Font("PingFang SC", Font.PLAIN, 12));
+ emailHintLabel.setForeground(Color.RED);
+ emailHintLabel.setBorder(BorderFactory.createEmptyBorder(0, 5, 0, 0));
+ emailContainer.add(emailHintLabel, BorderLayout.EAST);
// 楠岃瘉鐮� - 鏍囩宸﹀榻�
verificationCodeLabel = new JLabel("楠岃瘉鐮�");
@@ -281,13 +296,8 @@
passLabel.setAlignmentX(Component.LEFT_ALIGNMENT);
passField = new JPasswordField();
- passField.setMaximumSize(new Dimension(Integer.MAX_VALUE, 35));
passField.setFont(new Font("PingFang SC", Font.PLAIN, 14));
- passField.setBorder(BorderFactory.createCompoundBorder(
- BorderFactory.createLineBorder(new Color(200, 200, 200)),
- BorderFactory.createEmptyBorder(5, 8, 5, 8)
- ));
- passField.setAlignmentX(Component.LEFT_ALIGNMENT);
+ JPanel passPanel = createPasswordPanel(passField);
// 纭瀵嗙爜 - 鏍囩宸﹀榻�
confirmPassLabel = new JLabel("纭瀵嗙爜");
@@ -296,13 +306,20 @@
confirmPassLabel.setAlignmentX(Component.LEFT_ALIGNMENT);
confirmPassField = new JPasswordField();
- confirmPassField.setMaximumSize(new Dimension(Integer.MAX_VALUE, 35));
confirmPassField.setFont(new Font("PingFang SC", Font.PLAIN, 14));
- confirmPassField.setBorder(BorderFactory.createCompoundBorder(
- BorderFactory.createLineBorder(new Color(200, 200, 200)),
- BorderFactory.createEmptyBorder(5, 8, 5, 8)
- ));
- confirmPassField.setAlignmentX(Component.LEFT_ALIGNMENT);
+ JPanel confirmPassPanel = createPasswordPanel(confirmPassField);
+
+ // 瀵嗙爜涓嶄竴鑷存彁绀�
+ matchStatusLabel = new JLabel(" ");
+ matchStatusLabel.setFont(new Font("PingFang SC", Font.PLAIN, 12));
+ matchStatusLabel.setForeground(Color.RED);
+ matchStatusLabel.setAlignmentX(Component.LEFT_ALIGNMENT);
+
+ // 瀵嗙爜闀垮害鎻愮ず
+ passwordHintLabel = new JLabel(" ");
+ passwordHintLabel.setFont(new Font("PingFang SC", Font.PLAIN, 12));
+ passwordHintLabel.setForeground(Color.RED);
+ passwordHintLabel.setAlignmentX(Component.LEFT_ALIGNMENT);
// 娉ㄥ唽鎸夐挳 - 鍗曠嫭涓�琛岋紝闀垮害涓庢枃鏈鐩稿悓
registerButton = new JButton("娉ㄥ唽");
@@ -343,7 +360,7 @@
formPanel.add(Box.createRigidArea(new Dimension(0, 10)));
formPanel.add(emailLabel);
formPanel.add(Box.createRigidArea(new Dimension(0, 3)));
- formPanel.add(emailField);
+ formPanel.add(emailContainer);
formPanel.add(Box.createRigidArea(new Dimension(0, 10)));
formPanel.add(verificationCodeLabel);
formPanel.add(Box.createRigidArea(new Dimension(0, 3)));
@@ -353,12 +370,16 @@
formPanel.add(Box.createRigidArea(new Dimension(0, 10)));
formPanel.add(passLabel);
formPanel.add(Box.createRigidArea(new Dimension(0, 3)));
- formPanel.add(passField);
+ formPanel.add(passPanel);
formPanel.add(Box.createRigidArea(new Dimension(0, 10)));
formPanel.add(confirmPassLabel);
formPanel.add(Box.createRigidArea(new Dimension(0, 3)));
- formPanel.add(confirmPassField);
- formPanel.add(Box.createRigidArea(new Dimension(0, 20)));
+ formPanel.add(confirmPassPanel);
+ formPanel.add(Box.createRigidArea(new Dimension(0, 5)));
+ formPanel.add(matchStatusLabel);
+ formPanel.add(Box.createRigidArea(new Dimension(0, 5)));
+ formPanel.add(passwordHintLabel);
+ formPanel.add(Box.createRigidArea(new Dimension(0, 5)));
formPanel.add(registerButton);
formPanel.add(Box.createRigidArea(new Dimension(0, 8)));
formPanel.add(cancelButton);
@@ -383,6 +404,61 @@
// 鍥炶溅閿敞鍐�
confirmPassField.addActionListener(e -> performRegistration());
+
+ // 瀵嗙爜涓�鑷存�ф鏌�
+ DocumentListener matchListener = new DocumentListener() {
+ private void checkMatch() {
+ char[] p1 = passField.getPassword();
+ char[] p2 = confirmPassField.getPassword();
+ if (p2.length > 0 && p2.length == p1.length) {
+ if (!Arrays.equals(p1, p2)) {
+ matchStatusLabel.setText(getTranslationValue(currentLanguageCode, "password_mismatch_error", "涓ゆ杈撳叆鐨勫瘑鐮佷笉涓�鑷�"));
+ } else {
+ matchStatusLabel.setText(" ");
+ }
+ } else {
+ matchStatusLabel.setText(" ");
+ }
+ }
+ @Override
+ public void insertUpdate(DocumentEvent e) { checkMatch(); }
+ @Override
+ public void removeUpdate(DocumentEvent e) { checkMatch(); }
+ @Override
+ public void changedUpdate(DocumentEvent e) { checkMatch(); }
+ };
+ confirmPassField.getDocument().addDocumentListener(matchListener);
+ passField.getDocument().addDocumentListener(matchListener);
+
+ // 瀵嗙爜闀垮害妫�鏌�
+ passField.getDocument().addDocumentListener(new DocumentListener() {
+ private void checkLength() {
+ char[] password = passField.getPassword();
+ if (password.length > 0 && password.length < 6) {
+ passwordHintLabel.setText(getTranslationValue(currentLanguageCode, "password_length_error", "瀵嗙爜闀垮害涓嶈兘灏戜簬6浣�"));
+ } else {
+ passwordHintLabel.setText(" ");
+ }
+ }
+ public void insertUpdate(DocumentEvent e) { checkLength(); }
+ public void removeUpdate(DocumentEvent e) { checkLength(); }
+ public void changedUpdate(DocumentEvent e) { checkLength(); }
+ });
+
+ // 閭鏍煎紡妫�鏌�
+ emailField.getDocument().addDocumentListener(new DocumentListener() {
+ private void validate() {
+ String email = emailField.getText().trim();
+ if (!email.isEmpty() && !isValidEmail(email)) {
+ emailHintLabel.setText(getTranslationValue(currentLanguageCode, "invalid_email_error", "閭鏍煎紡閿欒"));
+ } else {
+ emailHintLabel.setText("");
+ }
+ }
+ public void insertUpdate(DocumentEvent e) { validate(); }
+ public void removeUpdate(DocumentEvent e) { validate(); }
+ public void changedUpdate(DocumentEvent e) { validate(); }
+ });
}
private void updateLanguage(String languageCode) {
@@ -399,6 +475,9 @@
registerButton.setText(getTranslationValue(languageCode, "register_button", registerButton.getText()));
cancelButton.setText(getTranslationValue(languageCode, "cancel_button", cancelButton.getText()));
sendCodeButton.setText(getTranslationValue(languageCode, "send_code_button", sendCodeButton.getText()));
+ if (passwordHintLabel != null) {
+ passwordHintLabel.setText(getTranslationValue(languageCode, "password_length_error", passwordHintLabel.getText()));
+ }
}
}
@@ -437,35 +516,51 @@
return;
}
- // 鐢熸垚闅忔満楠岃瘉鐮侊紙瀹為檯搴旂敤涓簲璇ラ�氳繃閭欢鍙戦�侊級
- generatedVerificationCode = generateRandomCode();
+ // 绂佺敤鎸夐挳锛岄槻姝㈤噸澶嶇偣鍑�
+ sendCodeButton.setEnabled(false);
- // 鍦ㄥ疄闄呭簲鐢ㄤ腑锛岃繖閲屽簲璇ヨ皟鐢ㄩ偖浠跺彂閫佹湇鍔�
- // 杩欓噷浠呮ā鎷熷彂閫佽繃绋�
- System.out.println("楠岃瘉鐮� " + generatedVerificationCode + " 宸插彂閫佸埌 " + email);
-
- // 鑾峰彇褰撳墠璇█鐨勭炕璇�
- Map<String, String> translationMap = translations.get(currentLanguageCode);
- if (translationMap != null) {
- JOptionPane.showMessageDialog(this,
- translationMap.get("verification_code_sent"),
- "鎻愮ず",
- JOptionPane.INFORMATION_MESSAGE);
- } else {
- JOptionPane.showMessageDialog(this,
- "楠岃瘉鐮佸凡鍙戦�佸埌鎮ㄧ殑閭",
- "鎻愮ず",
- JOptionPane.INFORMATION_MESSAGE);
- }
-
- // 寮�濮嬪�掕鏃�
- startCountdown();
- }
-
- // 鐢熸垚闅忔満楠岃瘉鐮�
- private String generateRandomCode() {
- // 鐢熸垚6浣嶉殢鏈烘暟瀛�
- return String.valueOf((int)((Math.random() * 9 + 1) * 100000));
+ // 鍦ㄦ柊绾跨▼涓皟鐢ˋPI锛岄伩鍏嶉樆濉濽I
+ new Thread(() -> {
+ try {
+ // 璋冪敤閭欢楠岃瘉鐮佸彂閫丄PI
+ EmailCodeSender.EmailCodeResponse response = EmailCodeSender.sendEmailCode(email);
+
+ // 鍦‥DT绾跨▼涓洿鏂癠I
+ SwingUtilities.invokeLater(() -> {
+ if (response.isSuccess()) {
+ // 鍙戦�佹垚鍔燂紝鏄剧ず鎻愮ず骞跺紑濮嬪�掕鏃�
+ Map<String, String> translationMap = translations.get(currentLanguageCode);
+ String successMessage = translationMap != null ?
+ translationMap.get("verification_code_sent") : "楠岃瘉鐮佸凡鍙戦�佸埌鎮ㄧ殑閭";
+ JOptionPane.showMessageDialog(this,
+ successMessage,
+ "鎻愮ず",
+ JOptionPane.INFORMATION_MESSAGE);
+
+ // 寮�濮�60绉掑�掕鏃�
+ startCountdown();
+ } else {
+ // 鍙戦�佸け璐ワ紝鏄剧ず閿欒淇℃伅骞舵仮澶嶆寜閽�
+ sendCodeButton.setEnabled(true);
+ String errorMessage = response.getMessage() != null ?
+ response.getMessage() : "楠岃瘉鐮佸彂閫佸け璐�";
+ JOptionPane.showMessageDialog(this,
+ errorMessage,
+ "閿欒",
+ JOptionPane.ERROR_MESSAGE);
+ }
+ });
+ } catch (Exception e) {
+ // 寮傚父澶勭悊锛屾仮澶嶆寜閽苟鏄剧ず閿欒
+ SwingUtilities.invokeLater(() -> {
+ sendCodeButton.setEnabled(true);
+ JOptionPane.showMessageDialog(this,
+ "鍙戦�侀獙璇佺爜鏃跺彂鐢熼敊璇�: " + e.getMessage(),
+ "閿欒",
+ JOptionPane.ERROR_MESSAGE);
+ });
+ }
+ }).start();
}
// 寮�濮嬪�掕鏃�
@@ -506,17 +601,19 @@
}
private void performRegistration() {
- String username = userField.getText().trim();
+ String nickname = userField.getText().trim();
String email = emailField.getText().trim();
- String verificationCode = verificationCodeField.getText().trim();
- String password = new String(passField.getPassword());
- String confirmPassword = new String(confirmPassField.getPassword());
+ String code = verificationCodeField.getText().trim();
+
+ // 鑾峰彇瀵嗙爜瀛楁鐨勫�硷紙涓庣櫥褰曢〉闈繚鎸佷竴鑷寸殑澶勭悊鏂瑰紡锛�
+ String password = new String(passField.getPassword()).trim();
+ String confirmPassword = new String(confirmPassField.getPassword()).trim();
// 鑾峰彇褰撳墠璇█鐨勭炕璇�
Map<String, String> translationMap = translations.get(currentLanguageCode);
// 杈撳叆楠岃瘉
- if (username.isEmpty() || email.isEmpty() || verificationCode.isEmpty() ||
+ if (nickname.isEmpty() || email.isEmpty() || code.isEmpty() ||
password.isEmpty() || confirmPassword.isEmpty()) {
String errorMessage = translationMap != null ?
translationMap.get("empty_fields_error") : "璇峰~鍐欐墍鏈夊瓧娈�";
@@ -553,19 +650,7 @@
return;
}
- // 楠岃瘉楠岃瘉鐮�
- if (!verificationCode.equals(generatedVerificationCode)) {
- String errorMessage = translationMap != null ?
- translationMap.get("invalid_verification_code") : "楠岃瘉鐮侀敊璇�";
- JOptionPane.showMessageDialog(this,
- errorMessage,
- "杈撳叆閿欒",
- JOptionPane.WARNING_MESSAGE);
- verificationCodeField.setText("");
- verificationCodeField.requestFocus();
- return;
- }
-
+ // 楠岃瘉涓ゆ杈撳叆鐨勫瘑鐮佹槸鍚︿竴鑷�
if (!password.equals(confirmPassword)) {
String errorMessage = translationMap != null ?
translationMap.get("password_mismatch_error") : "涓ゆ杈撳叆鐨勫瘑鐮佷笉涓�鑷�";
@@ -579,25 +664,51 @@
return;
}
- // 淇濆瓨鐢ㄦ埛淇℃伅
- UserChuShiHua.updateProperty("userName", username);
- UserChuShiHua.updateProperty("email", email);
- UserChuShiHua.updateProperty("password", password);
+ // 绂佺敤娉ㄥ唽鎸夐挳锛岄槻姝㈤噸澶嶆彁浜�
+ registerButton.setEnabled(false);
- String successMessage = translationMap != null ?
- translationMap.get("success_message") : "娉ㄥ唽鎴愬姛锛�";
- JOptionPane.showMessageDialog(this,
- successMessage,
- "鎴愬姛",
- JOptionPane.INFORMATION_MESSAGE);
-
- dispose();
-
- // 鑷姩濉厖鐧诲綍琛ㄥ崟
- if (parentFrame != null) {
- // 杩欓噷闇�瑕佽闂埗绐楀彛鐨剈sernameField锛屼絾鐢变簬灏佽鎬э紝鎴戜滑鍙兘闇�瑕佹坊鍔犲叕鍏辨柟娉�
- // 鏆傛椂鐣欑┖锛屽彲浠ユ牴鎹渶瑕佸疄鐜�
- }
+ // 鍦ㄦ柊绾跨▼涓皟鐢ˋPI锛岄伩鍏嶉樆濉濽I
+ new Thread(() -> {
+ try {
+ // 璋冪敤鐢ㄦ埛娉ㄥ唽API
+ UserRegister.RegisterResponse response = UserRegister.register(email, password, code, nickname,confirmPassword);
+
+ // 鍦‥DT绾跨▼涓洿鏂癠I
+ SwingUtilities.invokeLater(() -> {
+ registerButton.setEnabled(true);
+
+ if (response.isSuccess()) {
+ // 娉ㄥ唽鎴愬姛锛屾樉绀烘垚鍔熸彁绀�
+ String successMessage = translationMap != null ?
+ translationMap.get("success_message") : "娉ㄥ唽鎴愬姛锛�";
+ JOptionPane.showMessageDialog(this,
+ successMessage,
+ "鎴愬姛",
+ JOptionPane.INFORMATION_MESSAGE);
+
+ // 鍏抽棴娉ㄥ唽绐楀彛
+ dispose();
+ } else {
+ // 娉ㄥ唽澶辫触锛屾樉绀洪敊璇俊鎭�
+ String errorMessage = response.getMessage() != null ?
+ response.getMessage() : "娉ㄥ唽澶辫触";
+ JOptionPane.showMessageDialog(this,
+ errorMessage,
+ "娉ㄥ唽澶辫触",
+ JOptionPane.ERROR_MESSAGE);
+ }
+ });
+ } catch (Exception e) {
+ // 寮傚父澶勭悊锛屾仮澶嶆寜閽苟鏄剧ず閿欒
+ SwingUtilities.invokeLater(() -> {
+ registerButton.setEnabled(true);
+ JOptionPane.showMessageDialog(this,
+ "娉ㄥ唽鏃跺彂鐢熼敊璇�: " + e.getMessage(),
+ "閿欒",
+ JOptionPane.ERROR_MESSAGE);
+ });
+ }
+ }).start();
}
@Override
@@ -608,4 +719,47 @@
}
super.dispose();
}
+
+ private JPanel createPasswordPanel(JPasswordField passField) {
+ JPanel panel = new JPanel(new BorderLayout());
+ panel.setBackground(Color.WHITE);
+ panel.setBorder(BorderFactory.createCompoundBorder(
+ BorderFactory.createLineBorder(new Color(200, 200, 200)),
+ BorderFactory.createEmptyBorder(1, 1, 1, 1)
+ ));
+ panel.setMaximumSize(new Dimension(Integer.MAX_VALUE, 35));
+ panel.setAlignmentX(Component.LEFT_ALIGNMENT);
+
+ passField.setBorder(BorderFactory.createEmptyBorder(4, 8, 4, 8));
+ panel.add(passField, BorderLayout.CENTER);
+
+ JButton toggleBtn = new JButton();
+ try {
+ ImageIcon icon = new ImageIcon("image/look.png");
+ if (icon.getIconWidth() > 0) {
+ Image img = icon.getImage().getScaledInstance(20, 20, Image.SCALE_SMOOTH);
+ toggleBtn.setIcon(new ImageIcon(img));
+ } else {
+ toggleBtn.setText("馃憗");
+ }
+ } catch (Exception e) {
+ toggleBtn.setText("馃憗");
+ }
+
+ toggleBtn.setBorder(BorderFactory.createEmptyBorder(0, 5, 0, 5));
+ toggleBtn.setContentAreaFilled(false);
+ toggleBtn.setFocusPainted(false);
+ toggleBtn.setCursor(new Cursor(Cursor.HAND_CURSOR));
+
+ toggleBtn.addActionListener(e -> {
+ if (passField.getEchoChar() != 0) {
+ passField.setEchoChar((char) 0);
+ } else {
+ passField.setEchoChar('鈥�');
+ }
+ });
+
+ panel.add(toggleBtn, BorderLayout.EAST);
+ return panel;
+ }
}
\ No newline at end of file
diff --git a/src/dikuai/Dikuaiguanli.java b/src/dikuai/Dikuaiguanli.java
index b61db27..13c4755 100644
--- a/src/dikuai/Dikuaiguanli.java
+++ b/src/dikuai/Dikuaiguanli.java
@@ -1836,6 +1836,13 @@
if (landNumber == null || landNumber.trim().isEmpty()) {
return;
}
+
+ // 妫�鏌ユ槸鍚﹀凡缁忔槸褰撳墠宸ヤ綔鍦板潡锛屽鏋滄槸鍒欎笉閲嶅璁剧疆锛岄伩鍏嶉噸缃湴鍥捐鍥�
+ String sanitized = sanitizeLandNumber(landNumber);
+ if (Objects.equals(currentWorkLandNumber, sanitized)) {
+ return;
+ }
+
setCurrentWorkLand(landNumber, dikuai.getLandName());
}
diff --git a/src/login/ApiConfig.java b/src/login/ApiConfig.java
new file mode 100644
index 0000000..1f007d1
--- /dev/null
+++ b/src/login/ApiConfig.java
@@ -0,0 +1,93 @@
+package login;
+
+/**
+ * API閰嶇疆绫�
+ * 缁熶竴绠$悊API鍦板潃銆佽秴鏃舵椂闂寸瓑閰嶇疆
+ */
+public class ApiConfig {
+
+ private static final String DEFAULT_BASE_URL = "http://192.168.100.96:9000";
+ private static final int DEFAULT_CONNECT_TIMEOUT = 30000; // 30绉�
+ private static final int DEFAULT_READ_TIMEOUT = 60000; // 60绉�
+ private static final String DEFAULT_USER_AGENT = "LoginClient/1.0";
+
+ private final String baseUrl;
+ private final int connectTimeout;
+ private final int readTimeout;
+ private final String userAgent;
+
+ /**
+ * 绉佹湁鏋勯�犲嚱鏁�
+ */
+ private ApiConfig(String baseUrl, int connectTimeout, int readTimeout, String userAgent) {
+ this.baseUrl = baseUrl != null ? baseUrl : DEFAULT_BASE_URL;
+ this.connectTimeout = connectTimeout > 0 ? connectTimeout : DEFAULT_CONNECT_TIMEOUT;
+ this.readTimeout = readTimeout > 0 ? readTimeout : DEFAULT_READ_TIMEOUT;
+ this.userAgent = userAgent != null ? userAgent : DEFAULT_USER_AGENT;
+ }
+
+ /**
+ * 鑾峰彇榛樿閰嶇疆
+ */
+ public static ApiConfig getDefault() {
+ return new ApiConfig(DEFAULT_BASE_URL, DEFAULT_CONNECT_TIMEOUT, DEFAULT_READ_TIMEOUT, DEFAULT_USER_AGENT);
+ }
+
+ /**
+ * 鍒涘缓鑷畾涔夐厤缃�
+ */
+ public static Builder builder() {
+ return new Builder();
+ }
+
+ public String getBaseUrl() {
+ return baseUrl;
+ }
+
+ public int getConnectTimeout() {
+ return connectTimeout;
+ }
+
+ public int getReadTimeout() {
+ return readTimeout;
+ }
+
+ public String getUserAgent() {
+ return userAgent;
+ }
+
+ /**
+ * 閰嶇疆鏋勫缓鍣�
+ */
+ public static class Builder {
+ private String baseUrl;
+ private int connectTimeout;
+ private int readTimeout;
+ private String userAgent;
+
+ public Builder baseUrl(String baseUrl) {
+ this.baseUrl = baseUrl;
+ return this;
+ }
+
+ public Builder connectTimeout(int connectTimeout) {
+ this.connectTimeout = connectTimeout;
+ return this;
+ }
+
+ public Builder readTimeout(int readTimeout) {
+ this.readTimeout = readTimeout;
+ return this;
+ }
+
+ public Builder userAgent(String userAgent) {
+ this.userAgent = userAgent;
+ return this;
+ }
+
+ public ApiConfig build() {
+ return new ApiConfig(baseUrl, connectTimeout, readTimeout, userAgent);
+ }
+ }
+}
+
diff --git a/src/login/ApiResponse.java b/src/login/ApiResponse.java
new file mode 100644
index 0000000..6dcc55f
--- /dev/null
+++ b/src/login/ApiResponse.java
@@ -0,0 +1,76 @@
+package login;
+
+/**
+ * 閫氱敤API鍝嶅簲绫�
+ * 灏佽HTTP璇锋眰鐨勫搷搴旂粨鏋�
+ */
+public class ApiResponse {
+
+ private final boolean success;
+ private final int statusCode;
+ private final String responseBody;
+ private final String errorMessage;
+
+ /**
+ * 鏋勯�犲嚱鏁�
+ *
+ * @param success 璇锋眰鏄惁鎴愬姛
+ * @param statusCode HTTP鐘舵�佺爜
+ * @param responseBody 鍝嶅簲浣撳唴瀹�
+ * @param errorMessage 閿欒淇℃伅锛堝鏋滃け璐ワ級
+ */
+ public ApiResponse(boolean success, int statusCode, String responseBody, String errorMessage) {
+ this.success = success;
+ this.statusCode = statusCode;
+ this.responseBody = responseBody;
+ this.errorMessage = errorMessage;
+ }
+
+ /**
+ * 鍒涘缓鎴愬姛鍝嶅簲
+ */
+ public static ApiResponse success(int statusCode, String responseBody) {
+ return new ApiResponse(true, statusCode, responseBody, null);
+ }
+
+ /**
+ * 鍒涘缓澶辫触鍝嶅簲
+ */
+ public static ApiResponse failure(int statusCode, String errorMessage) {
+ return new ApiResponse(false, statusCode, null, errorMessage);
+ }
+
+ public boolean isSuccess() {
+ return success;
+ }
+
+ public int getStatusCode() {
+ return statusCode;
+ }
+
+ public String getResponseBody() {
+ return responseBody;
+ }
+
+ public String getErrorMessage() {
+ return errorMessage;
+ }
+
+ /**
+ * 鑾峰彇鍝嶅簲娑堟伅锛堟垚鍔熸椂杩斿洖鍝嶅簲浣擄紝澶辫触鏃惰繑鍥為敊璇俊鎭級
+ */
+ public String getMessage() {
+ return success ? responseBody : errorMessage;
+ }
+
+ @Override
+ public String toString() {
+ return "ApiResponse{" +
+ "success=" + success +
+ ", statusCode=" + statusCode +
+ ", responseBody='" + responseBody + '\'' +
+ ", errorMessage='" + errorMessage + '\'' +
+ '}';
+ }
+}
+
diff --git a/src/login/EmailCodeSender.java b/src/login/EmailCodeSender.java
new file mode 100644
index 0000000..37e0e8e
--- /dev/null
+++ b/src/login/EmailCodeSender.java
@@ -0,0 +1,134 @@
+package login;
+
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * 閭楠岃瘉鐮佸彂閫佸伐鍏风被
+ * 鐢ㄤ簬鍚戞寚瀹氶偖绠卞湴鍧�鍙戦�侀獙璇佺爜
+ * 閭鍦板潃閫氳繃URL鍙傛暟浼犻�掞紝璇锋眰浣撲负绌�
+ */
+public class EmailCodeSender {
+
+ private static final String SEND_CODE_API = "/api/email/send-code";
+
+ private final HttpClientLoca httpClient;
+ private final ApiConfig config;
+
+ /**
+ * 浣跨敤榛樿閰嶇疆鍒涘缓EmailCodeSender
+ */
+ public EmailCodeSender() {
+ this.config = ApiConfig.getDefault();
+ this.httpClient = new HttpClientLoca(config);
+ }
+
+ /**
+ * 浣跨敤鑷畾涔夐厤缃垱寤篍mailCodeSender
+ */
+ public EmailCodeSender(ApiConfig config) {
+ this.config = config != null ? config : ApiConfig.getDefault();
+ this.httpClient = new HttpClientLoca(this.config);
+ }
+
+ /**
+ * 鍙戦�侀偖绠遍獙璇佺爜璇锋眰锛堝疄渚嬫柟娉曪級
+ * 閭鍦板潃閫氳繃URL鍙傛暟浼犻�掞紝鏍煎紡锛�/api/email/send-code?email=xxx
+ * 璇锋眰浣撲负绌�
+ *
+ * @param email 閭鍦板潃
+ * @return EmailCodeResponse 鍖呭惈鍝嶅簲鐘舵�佺爜鍜屽搷搴斿唴瀹圭殑瀵硅薄
+ */
+ public EmailCodeResponse sendEmailCodeInstance(String email) {
+ // 鍙傛暟鏍¢獙
+ if (email == null || email.trim().isEmpty()) {
+ return EmailCodeResponse.failure(400, "閭鍦板潃涓嶈兘涓虹┖");
+ }
+
+ try {
+ // 鏋勫缓URL鍙傛暟
+ Map<String, String> params = new HashMap<>();
+ params.put("email", email);
+
+ // 鍙戦�丳OST璇锋眰锛圲RL鍙傛暟锛岃姹備綋涓虹┖锛�
+ String url = config.getBaseUrl() + SEND_CODE_API;
+ ApiResponse apiResponse = httpClient.post(url, params);
+
+ // 杞崲涓篍mailCodeResponse
+ if (apiResponse.isSuccess()) {
+ return EmailCodeResponse.success(apiResponse.getStatusCode(),
+ "楠岃瘉鐮佸彂閫佹垚鍔�", apiResponse.getResponseBody());
+ } else {
+ return EmailCodeResponse.failure(apiResponse.getStatusCode(),
+ apiResponse.getErrorMessage() != null ?
+ apiResponse.getErrorMessage() : "楠岃瘉鐮佸彂閫佸け璐�");
+ }
+ } catch (Exception e) {
+ return EmailCodeResponse.failure(500, "璇锋眰寮傚父: " + e.getMessage());
+ }
+ }
+
+ /**
+ * 闈欐�佹柟娉曪細浣跨敤榛樿閰嶇疆鍙戦�侀獙璇佺爜锛堜繚鎸佸悜鍚庡吋瀹癸級
+ */
+ public static EmailCodeResponse sendEmailCode(String email) {
+ return new EmailCodeSender().sendEmailCodeInstance(email);
+ }
+
+ /**
+ * 閭楠岃瘉鐮佸搷搴旂粨鏋滃皝瑁呯被
+ */
+ public static class EmailCodeResponse {
+ private final boolean success;
+ private final int statusCode;
+ private final String message;
+ private final String responseBody;
+
+ private EmailCodeResponse(boolean success, int statusCode, String message, String responseBody) {
+ this.success = success;
+ this.statusCode = statusCode;
+ this.message = message;
+ this.responseBody = responseBody;
+ }
+
+ /**
+ * 鍒涘缓鎴愬姛鍝嶅簲
+ */
+ public static EmailCodeResponse success(int statusCode, String message, String responseBody) {
+ return new EmailCodeResponse(true, statusCode, message, responseBody);
+ }
+
+ /**
+ * 鍒涘缓澶辫触鍝嶅簲
+ */
+ public static EmailCodeResponse failure(int statusCode, String message) {
+ return new EmailCodeResponse(false, statusCode, message, null);
+ }
+
+ public boolean isSuccess() {
+ return success;
+ }
+
+ public int getStatusCode() {
+ return statusCode;
+ }
+
+ public String getMessage() {
+ return message;
+ }
+
+ public String getResponseBody() {
+ return responseBody;
+ }
+
+ @Override
+ public String toString() {
+ return "EmailCodeResponse{" +
+ "success=" + success +
+ ", statusCode=" + statusCode +
+ ", message='" + message + '\'' +
+ ", responseBody='" + responseBody + '\'' +
+ '}';
+ }
+ }
+}
diff --git a/src/login/HttpClientLoca.java b/src/login/HttpClientLoca.java
new file mode 100644
index 0000000..d898685
--- /dev/null
+++ b/src/login/HttpClientLoca.java
@@ -0,0 +1,236 @@
+package login;
+
+import java.io.BufferedReader;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.io.OutputStream;
+import java.net.HttpURLConnection;
+import java.net.URL;
+import java.nio.charset.StandardCharsets;
+import java.util.Map;
+
+/**
+ * HTTP瀹㈡埛绔伐鍏风被
+ * 鎻愪緵缁熶竴鐨凥TTP璇锋眰澶勭悊锛屾敮鎸丟ET鍜孭OST璇锋眰
+ */
+public class HttpClientLoca {
+
+ private final ApiConfig config;
+
+ /**
+ * 浣跨敤榛樿閰嶇疆鍒涘缓HttpClient
+ */
+ public HttpClientLoca() {
+ this.config = ApiConfig.getDefault();
+ }
+
+ /**
+ * 浣跨敤鑷畾涔夐厤缃垱寤篐ttpClient
+ */
+ public HttpClientLoca(ApiConfig config) {
+ this.config = config != null ? config : ApiConfig.getDefault();
+ }
+
+ /**
+ * 鍙戦�丟ET璇锋眰
+ *
+ * @param url 璇锋眰URL
+ * @param params URL鍙傛暟锛堝彲閫夛紝key-value瀵癸級
+ * @return ApiResponse 鍝嶅簲缁撴灉
+ */
+ public ApiResponse get(String url, Map<String, String> params) {
+ try {
+ String fullUrl = buildUrl(url, params);
+ HttpURLConnection connection = createConnection(fullUrl, "GET", null);
+
+ try {
+ int statusCode = connection.getResponseCode();
+ String responseBody = readResponse(connection);
+ boolean success = statusCode >= 200 && statusCode < 300;
+
+ return new ApiResponse(success, statusCode, responseBody, null);
+ } finally {
+ disconnect(connection);
+ }
+ } catch (Exception e) {
+ return new ApiResponse(false, 500, null, "璇锋眰寮傚父: " + e.getMessage());
+ }
+ }
+
+ /**
+ * 鍙戦�丟ET璇锋眰锛堟棤鍙傛暟锛�
+ */
+ public ApiResponse get(String url) {
+ return get(url, null);
+ }
+
+ /**
+ * 鍙戦�丳OST璇锋眰锛圝SON鏍煎紡锛�
+ *
+ * @param url 璇锋眰URL
+ * @param jsonBody JSON璇锋眰浣�
+ * @return ApiResponse 鍝嶅簲缁撴灉
+ */
+ public ApiResponse postJson(String url, String jsonBody) {
+ try {
+ HttpURLConnection connection = createConnection(url, "POST", jsonBody);
+
+ try {
+ // 鍙戦�丣SON鏁版嵁
+ if (jsonBody != null && !jsonBody.isEmpty()) {
+ try (OutputStream outputStream = connection.getOutputStream()) {
+ byte[] jsonBytes = jsonBody.getBytes(StandardCharsets.UTF_8);
+ outputStream.write(jsonBytes);
+ outputStream.flush();
+ }
+ }
+
+ int statusCode = connection.getResponseCode();
+ String responseBody = readResponse(connection);
+ boolean success = statusCode >= 200 && statusCode < 300;
+
+ return new ApiResponse(success, statusCode, responseBody, null);
+ } finally {
+ disconnect(connection);
+ }
+ } catch (Exception e) {
+ return new ApiResponse(false, 500, null, "璇锋眰寮傚父: " + e.getMessage());
+ }
+ }
+
+ /**
+ * 鍙戦�丳OST璇锋眰锛圲RL鍙傛暟锛岃姹備綋涓虹┖锛�
+ *
+ * @param url 璇锋眰URL
+ * @param params URL鍙傛暟锛堝彲閫夛紝key-value瀵癸級
+ * @return ApiResponse 鍝嶅簲缁撴灉
+ */
+ public ApiResponse post(String url, Map<String, String> params) {
+ try {
+ String fullUrl = buildUrl(url, params);
+ HttpURLConnection connection = createConnection(fullUrl, "POST", null);
+
+ try {
+ // POST璇锋眰鍗充娇娌℃湁璇锋眰浣撲篃闇�瑕佽皟鐢╣etResponseCode鏉ヨЕ鍙戣姹傚彂閫�
+ int statusCode = connection.getResponseCode();
+ String responseBody = readResponse(connection);
+ boolean success = statusCode >= 200 && statusCode < 300;
+
+ return new ApiResponse(success, statusCode, responseBody, null);
+ } finally {
+ disconnect(connection);
+ }
+ } catch (Exception e) {
+ return new ApiResponse(false, 500, null, "璇锋眰寮傚父: " + e.getMessage());
+ }
+ }
+
+ /**
+ * 鍙戦�丳OST璇锋眰锛堟棤鍙傛暟锛岃姹備綋涓虹┖锛�
+ */
+ public ApiResponse post(String url) {
+ return post(url, null);
+ }
+
+ /**
+ * 鏋勫缓甯﹀弬鏁扮殑URL
+ */
+ private String buildUrl(String baseUrl, Map<String, String> params) throws Exception {
+ if (params == null || params.isEmpty()) {
+ return baseUrl;
+ }
+
+ StringBuilder urlBuilder = new StringBuilder(baseUrl);
+ boolean first = !baseUrl.contains("?");
+
+ for (Map.Entry<String, String> entry : params.entrySet()) {
+ if (first) {
+ urlBuilder.append("?");
+ first = false;
+ } else {
+ urlBuilder.append("&");
+ }
+
+ String key = java.net.URLEncoder.encode(entry.getKey(), StandardCharsets.UTF_8.name());
+ String value = java.net.URLEncoder.encode(entry.getValue(), StandardCharsets.UTF_8.name());
+ urlBuilder.append(key).append("=").append(value);
+ }
+
+ return urlBuilder.toString();
+ }
+
+ /**
+ * 鍒涘缓HTTP杩炴帴
+ */
+ private HttpURLConnection createConnection(String urlString, String method, String requestBody) throws Exception {
+ URL url = new URL(urlString);
+ HttpURLConnection connection = (HttpURLConnection) url.openConnection();
+
+ // 璁剧疆杩炴帴灞炴��
+ connection.setDoInput(true);
+ connection.setUseCaches(false);
+ connection.setRequestMethod(method);
+ connection.setConnectTimeout(config.getConnectTimeout());
+ connection.setReadTimeout(config.getReadTimeout());
+
+ // 璁剧疆璇锋眰澶�
+ connection.setRequestProperty("Accept", "application/json");
+ connection.setRequestProperty("User-Agent", config.getUserAgent());
+
+ // POST璇锋眰闇�瑕佽缃緭鍑哄拰Content-Type锛堜粎褰撴湁璇锋眰浣撴椂锛�
+ if ("POST".equals(method)) {
+ if (requestBody != null && !requestBody.isEmpty()) {
+ connection.setDoOutput(true);
+ connection.setRequestProperty("Content-Type", "application/json; charset=UTF-8");
+ } else {
+ // POST璇锋眰鍗充娇娌℃湁璇锋眰浣擄紝涔熼渶瑕佽缃瓺oOutput涓簍rue
+ connection.setDoOutput(true);
+ }
+ }
+
+ return connection;
+ }
+
+ /**
+ * 璇诲彇鍝嶅簲鍐呭
+ */
+ private String readResponse(HttpURLConnection connection) throws Exception {
+ int status = connection.getResponseCode();
+ InputStream inputStream;
+
+ if (status >= 200 && status < 300) {
+ inputStream = connection.getInputStream();
+ } else {
+ inputStream = connection.getErrorStream();
+ }
+
+ if (inputStream == null) {
+ return "";
+ }
+
+ StringBuilder response = new StringBuilder();
+ try (BufferedReader reader = new BufferedReader(
+ new InputStreamReader(inputStream, StandardCharsets.UTF_8))) {
+ String line;
+ while ((line = reader.readLine()) != null) {
+ response.append(line);
+ }
+ }
+
+ return response.toString();
+ }
+
+ /**
+ * 瀹夊叏鏂紑杩炴帴
+ */
+ private void disconnect(HttpURLConnection connection) {
+ if (connection != null) {
+ try {
+ connection.disconnect();
+ } catch (Exception e) {
+ // 蹇界暐鏂紑杩炴帴鏃剁殑寮傚父
+ }
+ }
+ }
+}
+
diff --git a/src/login/LoginTestRunner.java b/src/login/LoginTestRunner.java
new file mode 100644
index 0000000..8e07480
--- /dev/null
+++ b/src/login/LoginTestRunner.java
@@ -0,0 +1,106 @@
+package login;
+
+/**
+ * 鐧诲綍鍔熻兘娴嬭瘯杩愯绫�
+ * 鍙互鐩存帴杩愯姝ょ被鐨刴ain鏂规硶鏉ユ祴璇曠櫥褰曞姛鑳�
+ */
+public class LoginTestRunner {
+
+ public static void main(String[] args) {
+ System.out.println("========== 鐧诲綍鍔熻兘娴嬭瘯寮�濮� ==========\n");
+
+ // 娴嬭瘯閭楠岃瘉鐮佸彂閫�
+ //testSendEmailCode();
+
+ // 娴嬭瘯鐧诲綍楠岃瘉
+ testVerifyLogin();
+
+ // 娴嬭瘯鐢ㄦ埛娉ㄥ唽
+ //testUserRegister();
+
+
+ }
+
+ /**
+ * 娴嬭瘯鍙戦�侀偖绠遍獙璇佺爜
+ */
+ private static void testSendEmailCode() {
+ System.out.println("銆愭祴璇�1銆戝彂閫侀偖绠遍獙璇佺爜");
+ System.out.println("----------------------------------------");
+
+ // 娴嬭瘯姝e父閭
+ String testEmail = "979909237@qq.com";
+ System.out.println("娴嬭瘯閭: " + testEmail);
+
+ EmailCodeSender.EmailCodeResponse response = EmailCodeSender.sendEmailCode(testEmail);
+
+ System.out.println("璇锋眰缁撴灉:");
+ System.out.println(" 鉁� 鎴愬姛: " + response.isSuccess());
+ System.out.println(" 鉁� 鐘舵�佺爜: " + response.getStatusCode());
+ System.out.println(" 鉁� 娑堟伅: " + response.getMessage());
+ if (response.getResponseBody() != null && !response.getResponseBody().isEmpty()) {
+ System.out.println(" 鉁� 鍝嶅簲浣�: " + response.getResponseBody());
+ }
+ System.out.println();
+ }
+
+ /**
+ * 娴嬭瘯鐧诲綍楠岃瘉
+ */
+ private static void testVerifyLogin() {
+ System.out.println("銆愭祴璇�2銆戠櫥褰曢獙璇�");
+ System.out.println("----------------------------------------");
+
+ String email = "979909237@qq.com";
+ String password = "password123";
+
+ System.out.println("娴嬭瘯鍙傛暟:");
+ System.out.println(" - 閭: " + email);
+ System.out.println(" - 瀵嗙爜: " + password);
+
+ LoginVerifier.LoginVerifyResponse response = LoginVerifier.verifyLogin(email, password);
+
+ System.out.println("楠岃瘉缁撴灉:");
+ System.out.println(" 鉁� 鎴愬姛: " + response.isSuccess());
+ System.out.println(" 鉁� 鐘舵�佺爜: " + response.getStatusCode());
+ System.out.println(" 鉁� 娑堟伅: " + response.getMessage());
+ if (response.getResponseBody() != null && !response.getResponseBody().isEmpty()) {
+ System.out.println(" 鉁� 鍝嶅簲浣�: " + response.getResponseBody());
+ }
+ System.out.println();
+ }
+
+ /**
+ * 娴嬭瘯鐢ㄦ埛娉ㄥ唽
+ */
+ private static void testUserRegister() {
+ System.out.println("銆愭祴璇�3銆戠敤鎴锋敞鍐�");
+ System.out.println("----------------------------------------");
+
+ String email = "979909237@qq.com";
+ String password = "password123";
+ String code = "709212";
+ String nickname = "zshTest";
+
+ System.out.println("娴嬭瘯鍙傛暟:");
+ System.out.println(" - 閭: " + email);
+ System.out.println(" - 瀵嗙爜: " + password);
+ System.out.println(" - 楠岃瘉鐮�: " + code);
+ System.out.println(" - 鏄电О: " + nickname);
+
+ UserRegister.RegisterResponse response = UserRegister.register(email, password, code, nickname,password);
+
+ System.out.println("娉ㄥ唽缁撴灉:");
+ System.out.println(" 鉁� 鎴愬姛: " + response.isSuccess());
+ System.out.println(" 鉁� 鐘舵�佺爜: " + response.getStatusCode());
+ System.out.println(" 鉁� 娑堟伅: " + response.getMessage());
+ if (response.getResponseBody() != null && !response.getResponseBody().isEmpty()) {
+ System.out.println(" 鉁� 鍝嶅簲浣�: " + response.getResponseBody());
+ }
+ System.out.println();
+ }
+
+
+
+}
+
diff --git a/src/login/LoginVerifier.java b/src/login/LoginVerifier.java
new file mode 100644
index 0000000..bd7b884
--- /dev/null
+++ b/src/login/LoginVerifier.java
@@ -0,0 +1,245 @@
+package login;
+
+import com.fasterxml.jackson.databind.ObjectMapper;
+
+/**
+ * 鐧诲綍鏍¢獙宸ュ叿绫�
+ * 鐢ㄤ簬楠岃瘉閭楠岃瘉鐮佸拰瀵嗙爜
+ */
+public class LoginVerifier {
+
+ private static final String VERIFY_CODE_API = "/api/auth/login";
+
+ private final HttpClientLoca httpClient;
+ private final ApiConfig config;
+ private final ObjectMapper objectMapper;
+
+ /**
+ * 浣跨敤榛樿閰嶇疆鍒涘缓LoginVerifier
+ */
+ public LoginVerifier() {
+ this.config = ApiConfig.getDefault();
+ this.httpClient = new HttpClientLoca(config);
+ this.objectMapper = new ObjectMapper();
+ }
+
+ /**
+ * 浣跨敤鑷畾涔夐厤缃垱寤篖oginVerifier
+ */
+ public LoginVerifier(ApiConfig config) {
+ this.config = config != null ? config : ApiConfig.getDefault();
+ this.httpClient = new HttpClientLoca(this.config);
+ this.objectMapper = new ObjectMapper();
+ }
+
+ /**
+ * 楠岃瘉閭楠岃瘉鐮佸拰瀵嗙爜锛堝疄渚嬫柟娉曪級
+ *
+ * @param email 閭鍦板潃
+ * @param password 瀵嗙爜
+ * @return LoginVerifyResponse 鍖呭惈鍝嶅簲鐘舵�佺爜鍜屽搷搴斿唴瀹圭殑瀵硅薄
+ */
+ public LoginVerifyResponse verifyLoginInstance(String email, String password) {
+ // 鍙傛暟鏍¢獙
+ String validationError = validateParams(email, password);
+ if (validationError != null) {
+ return LoginVerifyResponse.failure(400, validationError);
+ }
+
+ try {
+ // 鏋勫缓璇锋眰浣揓SON
+ VerifyRequest request = new VerifyRequest(email, password);
+ String jsonData = objectMapper.writeValueAsString(request);
+
+ // 鍙戦�丳OST璇锋眰
+ String url = config.getBaseUrl() + VERIFY_CODE_API;
+ ApiResponse apiResponse = httpClient.postJson(url, jsonData);
+
+ // 瑙f瀽鍝嶅簲骞跺垽鏂槸鍚︽垚鍔�
+ boolean success = false;
+ String message = "楠岃瘉澶辫触";
+
+ if (apiResponse.getResponseBody() != null && !apiResponse.getResponseBody().isEmpty()) {
+ try {
+ LoginResponse loginResponse = objectMapper.readValue(
+ apiResponse.getResponseBody(), LoginResponse.class);
+ success = loginResponse.getCode() == 200;
+ message = loginResponse.getMessage();
+ } catch (Exception e) {
+ // JSON瑙f瀽澶辫触锛屼娇鐢℉TTP鐘舵�佺爜鍒ゆ柇
+ success = apiResponse.isSuccess();
+ message = success ? "楠岃瘉鎴愬姛" : "楠岃瘉澶辫触";
+ }
+ } else {
+ success = apiResponse.isSuccess();
+ message = apiResponse.getErrorMessage() != null ?
+ apiResponse.getErrorMessage() : "楠岃瘉澶辫触";
+ }
+
+ if (success) {
+ return LoginVerifyResponse.success(apiResponse.getStatusCode(),
+ message, apiResponse.getResponseBody());
+ } else {
+ return LoginVerifyResponse.failure(apiResponse.getStatusCode(), message);
+ }
+
+ } catch (Exception e) {
+ return LoginVerifyResponse.failure(500, "璇锋眰寮傚父: " + e.getMessage());
+ }
+ }
+
+ /**
+ * 鍙傛暟鏍¢獙
+ */
+ private String validateParams(String email, String password) {
+ if (email == null || email.trim().isEmpty()) {
+ return "閭鍦板潃涓嶈兘涓虹┖";
+ }
+
+ if (password == null || password.trim().isEmpty()) {
+ return "瀵嗙爜涓嶈兘涓虹┖";
+ }
+ return null;
+ }
+
+ /**
+ * 闈欐�佹柟娉曪細浣跨敤榛樿閰嶇疆楠岃瘉鐧诲綍锛堜繚鎸佸悜鍚庡吋瀹癸級
+ */
+ public static LoginVerifyResponse verifyLogin(String email, String password) {
+ return new LoginVerifier().verifyLoginInstance(email, password);
+ }
+
+ /**
+ * 楠岃瘉璇锋眰瀵硅薄
+ */
+ @SuppressWarnings("unused")
+ private static class VerifyRequest {
+ private String usernameOrEmail;
+
+ private String password;
+
+ public VerifyRequest(String usernameOrEmail, String password) {
+ this.usernameOrEmail = usernameOrEmail;
+
+ this.password = password;
+ }
+
+ public String getUsernameOrEmail() {
+ return usernameOrEmail;
+ }
+
+ public void setEmail(String usernameOrEmail) {
+ this.usernameOrEmail = usernameOrEmail;
+ }
+
+
+
+ public String getPassword() {
+ return password;
+ }
+
+ public void setPassword(String password) {
+ this.password = password;
+ }
+ }
+
+ /**
+ * 鐧诲綍鍝嶅簲瀵硅薄锛堝搴旀帴鍙f枃妗g殑鍝嶅簲鏍煎紡锛�
+ */
+ @SuppressWarnings("unused")
+ private static class LoginResponse {
+ private int code;
+ private String message;
+ private Object data;
+ private long timestamp;
+
+ public int getCode() {
+ return code;
+ }
+
+ public void setCode(int code) {
+ this.code = code;
+ }
+
+ public String getMessage() {
+ return message;
+ }
+
+ public void setMessage(String message) {
+ this.message = message;
+ }
+
+ public Object getData() {
+ return data;
+ }
+
+ public void setData(Object data) {
+ this.data = data;
+ }
+
+ public long getTimestamp() {
+ return timestamp;
+ }
+
+ public void setTimestamp(long timestamp) {
+ this.timestamp = timestamp;
+ }
+ }
+
+ /**
+ * 鐧诲綍楠岃瘉鍝嶅簲缁撴灉灏佽绫�
+ */
+ public static class LoginVerifyResponse {
+ private final boolean success;
+ private final int statusCode;
+ private final String message;
+ private final String responseBody;
+
+ private LoginVerifyResponse(boolean success, int statusCode, String message, String responseBody) {
+ this.success = success;
+ this.statusCode = statusCode;
+ this.message = message;
+ this.responseBody = responseBody;
+ }
+
+ /**
+ * 鍒涘缓鎴愬姛鍝嶅簲
+ */
+ public static LoginVerifyResponse success(int statusCode, String message, String responseBody) {
+ return new LoginVerifyResponse(true, statusCode, message, responseBody);
+ }
+
+ /**
+ * 鍒涘缓澶辫触鍝嶅簲
+ */
+ public static LoginVerifyResponse failure(int statusCode, String message) {
+ return new LoginVerifyResponse(false, statusCode, message, null);
+ }
+
+ public boolean isSuccess() {
+ return success;
+ }
+
+ public int getStatusCode() {
+ return statusCode;
+ }
+
+ public String getMessage() {
+ return message;
+ }
+
+ public String getResponseBody() {
+ return responseBody;
+ }
+
+ @Override
+ public String toString() {
+ return "LoginVerifyResponse{" +
+ "success=" + success +
+ ", statusCode=" + statusCode +
+ ", message='" + message + '\'' +
+ ", responseBody='" + responseBody + '\'' +
+ '}';
+ }
+ }
+}
diff --git a/src/login/PasswordReset.java b/src/login/PasswordReset.java
new file mode 100644
index 0000000..d948d39
--- /dev/null
+++ b/src/login/PasswordReset.java
@@ -0,0 +1,273 @@
+package login;
+
+
+import com.fasterxml.jackson.databind.ObjectMapper;
+
+/**
+ * 鎵惧洖瀵嗙爜宸ュ叿绫�
+ * 鐢ㄤ簬鐢ㄦ埛鎵惧洖瀵嗙爜鍔熻兘
+ */
+public class PasswordReset {
+
+ private static final String RESET_PASSWORD_API = "/api/auth/reset-password";
+
+ private final HttpClientLoca httpClient;
+ private final ApiConfig config;
+ private final ObjectMapper objectMapper;
+
+ /**
+ * 浣跨敤榛樿閰嶇疆鍒涘缓PasswordReset
+ */
+ public PasswordReset() {
+ this.config = ApiConfig.getDefault();
+ this.httpClient = new HttpClientLoca(config);
+ this.objectMapper = new ObjectMapper();
+ }
+
+ /**
+ * 浣跨敤鑷畾涔夐厤缃垱寤篜asswordReset
+ */
+ public PasswordReset(ApiConfig config) {
+ this.config = config != null ? config : ApiConfig.getDefault();
+ this.httpClient = new HttpClientLoca(this.config);
+ this.objectMapper = new ObjectMapper();
+ }
+
+ /**
+ * 鎵惧洖瀵嗙爜锛堝疄渚嬫柟娉曪級
+ *
+ * @param email 閭鍦板潃
+ * @param code 楠岃瘉鐮侊紙6浣嶆暟瀛楋級
+ * @param newPassword 鏂板瘑鐮�
+ * @param confirmPassword 纭瀵嗙爜
+ * @return ResetPasswordResponse 鍖呭惈鍝嶅簲鐘舵�佺爜鍜屽搷搴斿唴瀹圭殑瀵硅薄
+ */
+ public ResetPasswordResponse resetPasswordInstance(String email, String code, String newPassword, String confirmPassword) {
+ // 鍙傛暟鏍¢獙
+ String validationError = validateParams(email, code, newPassword, confirmPassword);
+ if (validationError != null) {
+ return ResetPasswordResponse.failure(400, validationError);
+ }
+
+ try {
+ // 鏋勫缓璇锋眰浣揓SON
+ ResetPasswordRequest request = new ResetPasswordRequest(email, code, newPassword, confirmPassword);
+ String jsonData = objectMapper.writeValueAsString(request);
+
+ // 鍙戦�丳OST璇锋眰
+ String url = config.getBaseUrl() + RESET_PASSWORD_API;
+ ApiResponse apiResponse = httpClient.postJson(url, jsonData);
+
+ // 瑙f瀽鍝嶅簲骞跺垽鏂槸鍚︽垚鍔�
+ boolean success = false;
+ String message = "瀵嗙爜閲嶇疆澶辫触";
+
+ if (apiResponse.getResponseBody() != null && !apiResponse.getResponseBody().isEmpty()) {
+ try {
+ ResetPasswordApiResponse resetResponse = objectMapper.readValue(
+ apiResponse.getResponseBody(), ResetPasswordApiResponse.class);
+ success = resetResponse.getCode() == 200;
+ message = resetResponse.getMessage();
+ } catch (Exception e) {
+ // JSON瑙f瀽澶辫触锛屼娇鐢℉TTP鐘舵�佺爜鍒ゆ柇
+ success = apiResponse.isSuccess();
+ message = success ? "瀵嗙爜閲嶇疆鎴愬姛" : "瀵嗙爜閲嶇疆澶辫触";
+ }
+ } else {
+ success = apiResponse.isSuccess();
+ message = apiResponse.getErrorMessage() != null ?
+ apiResponse.getErrorMessage() : "瀵嗙爜閲嶇疆澶辫触";
+ }
+
+ if (success) {
+ return ResetPasswordResponse.success(apiResponse.getStatusCode(),
+ message, apiResponse.getResponseBody());
+ } else {
+ return ResetPasswordResponse.failure(apiResponse.getStatusCode(), message);
+ }
+
+ } catch (Exception e) {
+ return ResetPasswordResponse.failure(500, "璇锋眰寮傚父: " + e.getMessage());
+ }
+ }
+
+ /**
+ * 鍙傛暟鏍¢獙
+ */
+ private String validateParams(String email, String code, String newPassword, String confirmPassword) {
+ if (email == null || email.trim().isEmpty()) {
+ return "閭鍦板潃涓嶈兘涓虹┖";
+ }
+ if (code == null || code.trim().isEmpty()) {
+ return "楠岃瘉鐮佷笉鑳戒负绌�";
+ }
+ if (newPassword == null || newPassword.trim().isEmpty()) {
+ return "鏂板瘑鐮佷笉鑳戒负绌�";
+ }
+ if (confirmPassword == null || confirmPassword.trim().isEmpty()) {
+ return "纭瀵嗙爜涓嶈兘涓虹┖";
+ }
+ if (!newPassword.equals(confirmPassword)) {
+ return "鏂板瘑鐮佸拰纭瀵嗙爜涓嶄竴鑷�";
+ }
+ return null;
+ }
+
+ /**
+ * 闈欐�佹柟娉曪細浣跨敤榛樿閰嶇疆閲嶇疆瀵嗙爜锛堜繚鎸佸悜鍚庡吋瀹癸級
+ */
+ public static ResetPasswordResponse resetPassword(String email, String code, String newPassword, String confirmPassword) {
+ return new PasswordReset().resetPasswordInstance(email, code, newPassword, confirmPassword);
+ }
+
+ /**
+ * 閲嶇疆瀵嗙爜璇锋眰瀵硅薄
+ */
+ @SuppressWarnings("unused")
+ private static class ResetPasswordRequest {
+ private String email;
+ private String code;
+ private String newPassword;
+ private String confirmPassword;
+
+ public ResetPasswordRequest(String email, String code, String newPassword, String confirmPassword) {
+ this.email = email;
+ this.code = code;
+ this.newPassword = newPassword;
+ this.confirmPassword = confirmPassword;
+ }
+
+ public String getEmail() {
+ return email;
+ }
+
+ public void setEmail(String email) {
+ this.email = email;
+ }
+
+ public String getCode() {
+ return code;
+ }
+
+ public void setCode(String code) {
+ this.code = code;
+ }
+
+ public String getNewPassword() {
+ return newPassword;
+ }
+
+ public void setNewPassword(String newPassword) {
+ this.newPassword = newPassword;
+ }
+
+ public String getConfirmPassword() {
+ return confirmPassword;
+ }
+
+ public void setConfirmPassword(String confirmPassword) {
+ this.confirmPassword = confirmPassword;
+ }
+ }
+
+ /**
+ * 閲嶇疆瀵嗙爜鍝嶅簲瀵硅薄锛堝搴旀帴鍙f枃妗g殑鍝嶅簲鏍煎紡锛�
+ */
+ @SuppressWarnings("unused")
+ private static class ResetPasswordApiResponse {
+ private int code;
+ private String message;
+ private Object data;
+ private long timestamp;
+
+ public int getCode() {
+ return code;
+ }
+
+ public void setCode(int code) {
+ this.code = code;
+ }
+
+ public String getMessage() {
+ return message;
+ }
+
+ public void setMessage(String message) {
+ this.message = message;
+ }
+
+ public Object getData() {
+ return data;
+ }
+
+ public void setData(Object data) {
+ this.data = data;
+ }
+
+ public long getTimestamp() {
+ return timestamp;
+ }
+
+ public void setTimestamp(long timestamp) {
+ this.timestamp = timestamp;
+ }
+ }
+
+ /**
+ * 閲嶇疆瀵嗙爜鍝嶅簲缁撴灉灏佽绫�
+ */
+ public static class ResetPasswordResponse {
+ private final boolean success;
+ private final int statusCode;
+ private final String message;
+ private final String responseBody;
+
+ private ResetPasswordResponse(boolean success, int statusCode, String message, String responseBody) {
+ this.success = success;
+ this.statusCode = statusCode;
+ this.message = message;
+ this.responseBody = responseBody;
+ }
+
+ /**
+ * 鍒涘缓鎴愬姛鍝嶅簲
+ */
+ public static ResetPasswordResponse success(int statusCode, String message, String responseBody) {
+ return new ResetPasswordResponse(true, statusCode, message, responseBody);
+ }
+
+ /**
+ * 鍒涘缓澶辫触鍝嶅簲
+ */
+ public static ResetPasswordResponse failure(int statusCode, String message) {
+ return new ResetPasswordResponse(false, statusCode, message, null);
+ }
+
+ public boolean isSuccess() {
+ return success;
+ }
+
+ public int getStatusCode() {
+ return statusCode;
+ }
+
+ public String getMessage() {
+ return message;
+ }
+
+ public String getResponseBody() {
+ return responseBody;
+ }
+
+ @Override
+ public String toString() {
+ return "ResetPasswordResponse{" +
+ "success=" + success +
+ ", statusCode=" + statusCode +
+ ", message='" + message + '\'' +
+ ", responseBody='" + responseBody + '\'' +
+ '}';
+ }
+ }
+}
+
diff --git a/src/login/UserRegister.java b/src/login/UserRegister.java
new file mode 100644
index 0000000..e1dfe47
--- /dev/null
+++ b/src/login/UserRegister.java
@@ -0,0 +1,280 @@
+package login;
+
+import com.fasterxml.jackson.databind.ObjectMapper;
+
+/**
+ * 鐢ㄦ埛娉ㄥ唽宸ュ叿绫�
+ * 鐢ㄤ簬鐢ㄦ埛娉ㄥ唽鍔熻兘
+ */
+public class UserRegister {
+
+ private static final String REGISTER_API = "/api/auth/register";
+
+ private final HttpClientLoca httpClient;
+ private final ApiConfig config;
+ private final ObjectMapper objectMapper;
+
+ /**
+ * 浣跨敤榛樿閰嶇疆鍒涘缓UserRegister
+ */
+ public UserRegister() {
+ this.config = ApiConfig.getDefault();
+ this.httpClient = new HttpClientLoca(config);
+ this.objectMapper = new ObjectMapper();
+ }
+
+ /**
+ * 浣跨敤鑷畾涔夐厤缃垱寤篣serRegister
+ */
+ public UserRegister(ApiConfig config) {
+ this.config = config != null ? config : ApiConfig.getDefault();
+ this.httpClient = new HttpClientLoca(this.config);
+ this.objectMapper = new ObjectMapper();
+ }
+
+ /**
+ * 鐢ㄦ埛娉ㄥ唽锛堝疄渚嬫柟娉曪級
+ *
+ * @param email 閭鍦板潃
+ * @param password 瀵嗙爜
+ * @param code 楠岃瘉鐮侊紙6浣嶆暟瀛楋級
+ * @param nickname 鐢ㄦ埛鏄电О
+ * @return RegisterResponse 鍖呭惈鍝嶅簲鐘舵�佺爜鍜屽搷搴斿唴瀹圭殑瀵硅薄
+ */
+ public RegisterResponse registerInstance(String email, String password, String code, String nickname,String confirmPassword) {
+ // 鍙傛暟鏍¢獙
+ String validationError = validateParams(email, password, code, nickname);
+ if (validationError != null) {
+ return RegisterResponse.failure(400, validationError);
+ }
+
+ try {
+ // 鏋勫缓璇锋眰浣揓SON
+ RegisterRequest request = new RegisterRequest(email, password, code, nickname,confirmPassword);
+ String jsonData = objectMapper.writeValueAsString(request);
+
+ // 鍙戦�丳OST璇锋眰
+ String url = config.getBaseUrl() + REGISTER_API;
+ ApiResponse apiResponse = httpClient.postJson(url, jsonData);
+
+ // 瑙f瀽鍝嶅簲骞跺垽鏂槸鍚︽垚鍔�
+ boolean success = false;
+ String message = "娉ㄥ唽澶辫触";
+
+ if (apiResponse.getResponseBody() != null && !apiResponse.getResponseBody().isEmpty()) {
+ try {
+ RegisterApiResponse registerResponse = objectMapper.readValue(
+ apiResponse.getResponseBody(), RegisterApiResponse.class);
+ success = registerResponse.getCode() == 200;
+ message = registerResponse.getMessage();
+ } catch (Exception e) {
+ // JSON瑙f瀽澶辫触锛屼娇鐢℉TTP鐘舵�佺爜鍒ゆ柇
+ success = apiResponse.isSuccess();
+ message = success ? "娉ㄥ唽鎴愬姛" : "娉ㄥ唽澶辫触";
+ }
+ } else {
+ success = apiResponse.isSuccess();
+ message = apiResponse.getErrorMessage() != null ?
+ apiResponse.getErrorMessage() : "娉ㄥ唽澶辫触";
+ }
+
+ if (success) {
+ return RegisterResponse.success(apiResponse.getStatusCode(),
+ message, apiResponse.getResponseBody());
+ } else {
+ return RegisterResponse.failure(apiResponse.getStatusCode(), message);
+ }
+
+ } catch (Exception e) {
+ return RegisterResponse.failure(500, "璇锋眰寮傚父: " + e.getMessage());
+ }
+ }
+
+ /**
+ * 鍙傛暟鏍¢獙
+ */
+ private String validateParams(String email, String password, String code, String nickname) {
+ if (email == null || email.trim().isEmpty()) {
+ return "閭鍦板潃涓嶈兘涓虹┖";
+ }
+ if (password == null || password.trim().isEmpty()) {
+ return "瀵嗙爜涓嶈兘涓虹┖";
+ }
+ if (code == null || code.trim().isEmpty()) {
+ return "楠岃瘉鐮佷笉鑳戒负绌�";
+ }
+ if (nickname == null || nickname.trim().isEmpty()) {
+ return "鐢ㄦ埛鏄电О涓嶈兘涓虹┖";
+ }
+ return null;
+ }
+
+ /**
+ * 闈欐�佹柟娉曪細浣跨敤榛樿閰嶇疆娉ㄥ唽锛堜繚鎸佸悜鍚庡吋瀹癸級
+ */
+ public static RegisterResponse register(String email, String password, String code, String nickname,String confirmPassword) {
+ return new UserRegister().registerInstance(email, password, code, nickname,confirmPassword);
+ }
+
+ /**
+ * 娉ㄥ唽璇锋眰瀵硅薄
+ */
+ @SuppressWarnings("unused")
+ private static class RegisterRequest {
+ private String email;
+ private String password;
+ private String confirmPassword;
+ private String code;
+ private String username;
+
+ public RegisterRequest(String email, String password, String code, String nickname,String confirmPassword) {
+ this.email = email;
+ this.password = password;
+ this.code = code;
+ this.username = nickname;
+ this.confirmPassword = confirmPassword;
+ }
+
+ public String getEmail() {
+ return email;
+ }
+
+ public void setEmail(String email) {
+ this.email = email;
+ }
+
+ public String getPassword() {
+ return password;
+ }
+
+ public void setPassword(String password) {
+ this.password = password;
+ }
+
+ public String getCode() {
+ return code;
+ }
+
+ public void setCode(String code) {
+ this.code = code;
+ }
+
+
+ public String getConfirmPassword() {
+ return confirmPassword;
+ }
+
+ public void setConfirmPassword(String confirmPassword) {
+ this.confirmPassword = confirmPassword;
+ }
+
+ public String getUsername() {
+ return username;
+ }
+
+ public void setUsername(String username) {
+ this.username = username;
+ }
+ }
+
+ /**
+ * 娉ㄥ唽鍝嶅簲瀵硅薄锛堝搴旀帴鍙f枃妗g殑鍝嶅簲鏍煎紡锛�
+ */
+ @SuppressWarnings("unused")
+ private static class RegisterApiResponse {
+ private int code;
+ private String message;
+ private Object data;
+ private long timestamp;
+
+ public int getCode() {
+ return code;
+ }
+
+ public void setCode(int code) {
+ this.code = code;
+ }
+
+ public String getMessage() {
+ return message;
+ }
+
+ public void setMessage(String message) {
+ this.message = message;
+ }
+
+ public Object getData() {
+ return data;
+ }
+
+ public void setData(Object data) {
+ this.data = data;
+ }
+
+ public long getTimestamp() {
+ return timestamp;
+ }
+
+ public void setTimestamp(long timestamp) {
+ this.timestamp = timestamp;
+ }
+ }
+
+ /**
+ * 鐢ㄦ埛娉ㄥ唽鍝嶅簲缁撴灉灏佽绫�
+ */
+ public static class RegisterResponse {
+ private final boolean success;
+ private final int statusCode;
+ private final String message;
+ private final String responseBody;
+
+ private RegisterResponse(boolean success, int statusCode, String message, String responseBody) {
+ this.success = success;
+ this.statusCode = statusCode;
+ this.message = message;
+ this.responseBody = responseBody;
+ }
+
+ /**
+ * 鍒涘缓鎴愬姛鍝嶅簲
+ */
+ public static RegisterResponse success(int statusCode, String message, String responseBody) {
+ return new RegisterResponse(true, statusCode, message, responseBody);
+ }
+
+ /**
+ * 鍒涘缓澶辫触鍝嶅簲
+ */
+ public static RegisterResponse failure(int statusCode, String message) {
+ return new RegisterResponse(false, statusCode, message, null);
+ }
+
+ public boolean isSuccess() {
+ return success;
+ }
+
+ public int getStatusCode() {
+ return statusCode;
+ }
+
+ public String getMessage() {
+ return message;
+ }
+
+ public String getResponseBody() {
+ return responseBody;
+ }
+
+ @Override
+ public String toString() {
+ return "RegisterResponse{" +
+ "success=" + success +
+ ", statusCode=" + statusCode +
+ ", message='" + message + '\'' +
+ ", responseBody='" + responseBody + '\'' +
+ '}';
+ }
+ }
+}
+
diff --git a/src/lujing/AoxinglujingHaveObstacel.java b/src/lujing/AoxinglujingHaveObstacel.java
index 5e2f046..ded40ab 100644
--- a/src/lujing/AoxinglujingHaveObstacel.java
+++ b/src/lujing/AoxinglujingHaveObstacel.java
@@ -182,7 +182,30 @@
private static List<Obstacle> parseObstacles(String obsStr, double margin) {
List<Obstacle> list = new ArrayList<>();
if (obsStr == null || obsStr.isEmpty()) return list;
- for (String part : obsStr.split("\\$")) {
+
+ // 鍏煎涓ょ鏍煎紡锛�
+ // 1. 鎷彿鍒嗛殧锛�(x1,y1;x2,y2)(x3,y3;x4,y4)
+ // 2. $鍒嗛殧锛歺1,y1;x2,y2$x3,y3;x4,y4
+
+ String[] groups;
+ if (obsStr.contains("(") && obsStr.contains(")")) {
+ // 澶勭悊鎷彿鏍煎紡
+ // 绉婚櫎鎵�鏈夌┖鐧藉瓧绗�
+ String cleanStr = obsStr.replaceAll("\\s+", "");
+ // 鎻愬彇鎷彿鍐呯殑鍐呭
+ List<String> parts = new ArrayList<>();
+ java.util.regex.Matcher m = java.util.regex.Pattern.compile("\\(([^)]+)\\)").matcher(cleanStr);
+ while (m.find()) {
+ parts.add(m.group(1));
+ }
+ groups = parts.toArray(new String[0]);
+ } else {
+ // 澶勭悊$鍒嗛殧鏍煎紡
+ groups = obsStr.split("\\$");
+ }
+
+ for (String part : groups) {
+ if (part == null || part.trim().isEmpty()) continue;
List<Point> pts = parseCoords(part);
if (pts.size() == 2) {
double r = dist(pts.get(0), pts.get(1));
diff --git a/src/lujing/YixinglujingHaveObstacel.java b/src/lujing/YixinglujingHaveObstacel.java
index ff0736a..c864d3a 100644
--- a/src/lujing/YixinglujingHaveObstacel.java
+++ b/src/lujing/YixinglujingHaveObstacel.java
@@ -1,80 +1,319 @@
package lujing;
import java.util.ArrayList;
-import java.util.Arrays;
import java.util.Collections;
import java.util.List;
/**
- * 寮傚舰鑽夊湴璺緞瑙勫垝 - 閬块殰澧炲己鐗� V8.0
- * 淇璇存槑锛�
- * 1. 淇浜嗗湴鍧楀唴缂╁拰闅滅鐗╁鎵╃殑姝h礋閫昏緫銆�
- * 2. 浼樺寲浜嗗杈瑰舰鍋忕Щ绠楁硶锛岀‘淇濋�嗘椂閽堢偣搴忎笅姝e�煎唴缂╋紝璐熷�煎鎵┿��
- * 3. 澧炲己浜嗛殰纰嶇墿瑙f瀽鐨勫仴澹�с��
+ * 寮傚舰鑽夊湴璺緞瑙勫垝 - 闅滅鐗╄鍓紭鍖栫増 V9.0
+ * 鏍稿績閫昏緫锛氬厛鐢熸垚鍏ㄨ鐩栨壂鎻忚矾寰勶紝鍐嶅埄鐢ㄥ鎵╁悗鐨勯殰纰嶇墿瀵硅矾寰勮繘琛岃鍓��
*/
public class YixinglujingHaveObstacel {
+ /**
+ * 瑙勫垝璺緞涓诲叆鍙�
+ */
public static List<PathSegment> planPath(String coordinates, String obstaclesStr, String widthStr, String marginStr) {
+ // 1. 瑙f瀽鍙傛暟
List<Point> rawPoints = parseCoordinates(coordinates);
if (rawPoints.size() < 3) return new ArrayList<>();
double mowWidth = Double.parseDouble(widthStr);
double safeMargin = Double.parseDouble(marginStr);
- // 1. 棰勫鐞嗗湴鍧楋紙纭繚閫嗘椂閽堥『搴忥級
+ // 2. 棰勫鐞嗗湴鍧楄竟鐣� (纭繚閫嗘椂閽�)
ensureCounterClockwise(rawPoints);
- // 銆愭牳蹇冧慨澶嶃�戯細瀵逛簬閫嗘椂閽堝杈瑰舰锛屾鏁版槸鍚戝唴鍋忕Щ锛圛nset锛�
- List<Point> boundary = getOffsetPolygon(rawPoints, safeMargin);
- if (boundary.size() < 3) return new ArrayList<>();
+ // 3. 鐢熸垚鍦板潡鍐呯缉鐨勫畨鍏ㄤ綔涓氳竟鐣� (Inset)
+ List<Point> mowingBoundary = getOffsetPolygon(rawPoints, safeMargin); // 姝f暟鍐呯缉
+ if (mowingBoundary.size() < 3) return new ArrayList<>();
- // 2. 纭畾鏈�浼樿搴﹀苟瑙勫垝鍩虹璺緞
- double bestAngle = findOptimalAngle(boundary);
- Point firstScanStart = getFirstScanPoint(boundary, mowWidth, bestAngle);
- List<Point> alignedBoundary = alignBoundaryStart(boundary, firstScanStart);
+ // 4. 绗竴姝ワ細鐢熸垚鈥滄棤瑙嗛殰纰嶇墿鈥濈殑鍏ㄨ鐩栨壂鎻忚矾寰�
+ // 鐩存帴浣跨敤鎵弿绾跨畻娉曠敓鎴愬~婊℃暣涓唴缂╄竟鐣岀殑璺緞
+ List<PathSegment> rawPath = generateFullCoveragePath(mowingBoundary, mowWidth);
- List<PathSegment> baseLines = new ArrayList<>();
- // 绗竴闃舵锛氬洿杈硅矾寰�
- for (int i = 0; i < alignedBoundary.size(); i++) {
- baseLines.add(new PathSegment(alignedBoundary.get(i), alignedBoundary.get((i + 1) % alignedBoundary.size()), true));
- }
- // 绗簩闃舵锛氱敓鎴愬唴閮ㄦ壂鎻忚矾寰�
- Point lastEdgePos = alignedBoundary.get(0);
- baseLines.addAll(generateGlobalScanPath(boundary, mowWidth, bestAngle, lastEdgePos));
-
- // 3. 澶勭悊闅滅鐗╋細瑙f瀽骞舵墽琛屻�愬鎵┿��
- // 銆愭牳蹇冧慨澶嶃�戯細瀵逛簬閫嗘椂閽堥殰纰嶇墿锛岃礋鏁版槸鍚戝鍋忕Щ锛圤utset锛�
+ // 5. 瑙f瀽闅滅鐗╁苟杩涜澶栨墿 (Outset)
+ // 娉ㄦ剰锛氶殰纰嶇墿澶栨墿璺濈 = 鍓茶崏鏈哄畨鍏ㄨ竟璺濓紝纭繚涓嶅彂鐢熺鎾�
List<Obstacle> obstacles = parseObstacles(obstaclesStr, safeMargin);
- // 4. 璺緞瑁佸壀涓庝紭鍖栬繛鎺�
- return optimizeAndClipPath(baseLines, obstacles);
- }
-
- private static List<Obstacle> parseObstacles(String obsStr, double margin) {
- List<Obstacle> obstacles = new ArrayList<>();
- if (obsStr == null || obsStr.trim().isEmpty()) return obstacles;
-
- for (String group : obsStr.split("\\$")) {
- List<Point> pts = parseCoordinates(group);
- if (pts.isEmpty()) continue;
-
- if (pts.size() == 2) {
- // 鍦嗗舰闅滅鐗╋細绗竴涓偣蹇冿紝绗簩涓偣涓婁竴鐐癸紝鍗婂緞澧炲姞 margin
- double r = Math.hypot(pts.get(0).x - pts.get(1).x, pts.get(0).y - pts.get(1).y);
- obstacles.add(new CircleObstacle(pts.get(0), r + margin));
- } else if (pts.size() > 2) {
- // 澶氳竟褰㈤殰纰嶇墿锛氱‘淇濋�嗘椂閽堬紝鐒跺悗浣跨敤璐� margin 杩涜銆愬鎵┿��
- ensureCounterClockwise(pts);
- obstacles.add(new PolyObstacle(getOffsetPolygon(pts, -margin)));
- }
- }
- return obstacles;
+ // 6. 绗簩姝ワ細浣跨敤闅滅鐗╄鍓矾寰� (鏍稿績姝ラ)
+ return clipPathWithObstacles(rawPath, obstacles);
}
/**
- * 澶氳竟褰㈠亸绉荤畻娉曪細鍩轰簬瑙掑钩鍒嗙嚎鍋忕Щ
- * 鍦ㄩ�嗘椂閽堥『搴忎笅锛歰ffset > 0 涓哄唴缂╋紝offset < 0 涓哄鎵�
+ * 浣跨敤闅滅鐗╅泦鍚堣鍓師濮嬭矾寰�
*/
+ private static List<PathSegment> clipPathWithObstacles(List<PathSegment> rawPath, List<Obstacle> obstacles) {
+ List<PathSegment> finalPath = new ArrayList<>();
+ Point currentPos = (rawPath.isEmpty()) ? new Point(0,0) : rawPath.get(0).start;
+
+ for (PathSegment segment : rawPath) {
+ // 灏嗗綋鍓嶈繖涓�娈佃矾寰勶紝鎷垮幓璺熸墍鏈夐殰纰嶇墿杩涜纰版挒妫�娴嬪拰瑁佸壀
+ // 鍒濆鏃讹紝杩欎竴娈垫槸瀹屾暣鐨�
+ List<PathSegment> segmentsToProcess = new ArrayList<>();
+ segmentsToProcess.add(segment);
+
+ for (Obstacle obs : obstacles) {
+ List<PathSegment> nextIterSegments = new ArrayList<>();
+ for (PathSegment seg : segmentsToProcess) {
+ // 濡傛灉鏄壊鑽夎矾寰勶紝闇�瑕佽鍓紱濡傛灉鏄┖璧拌矾寰勶紝閫氬父涔熼渶瑕侀伩闅滐紝
+ // 浣嗚繖閲屼富瑕佸鐞嗘壂鎻忕嚎鐨勮鍓��
+ if (seg.isMowing) {
+ nextIterSegments.addAll(obs.clip(seg));
+ } else {
+ // 绌鸿蛋璺緞鏆傛椂淇濈暀锛堥珮绾ч伩闅滈渶瑕丄*绠楁硶锛屾澶勭畝鍖栦负淇濈暀锛�
+ nextIterSegments.add(seg);
+ }
+ }
+ segmentsToProcess = nextIterSegments;
+ }
+
+ // 灏嗚鍓悗鍓╀綑鐨勭嚎娈靛姞鍏ユ渶缁堣矾寰�
+ for (PathSegment s : segmentsToProcess) {
+ // 杩囨护鎺夊洜涓鸿鍓骇鐢熺殑鏋佺煭绾挎
+ if (distance(s.start, s.end) < 0.05) continue;
+
+ // 濡傛灉褰撳墠鐐瑰拰绾挎璧风偣涓嶈繛璐紝鍔犲叆杩炴帴璺緞锛堢┖璧帮級
+ if (distance(currentPos, s.start) > 0.05) {
+ finalPath.add(new PathSegment(currentPos, s.start, false));
+ }
+
+ finalPath.add(s);
+ currentPos = s.end;
+ }
+ }
+ return finalPath;
+ }
+
+ // --- 璺緞鐢熸垚鏍稿績绠楁硶 (绉绘鑷� NoObstacle 绫�) ---
+
+ private static List<PathSegment> generateFullCoveragePath(List<Point> boundary, double width) {
+ // 1. 瀵绘壘鏈�浼樿搴�
+ double angle = findOptimalAngle(boundary);
+
+ // 2. 鏃嬭浆澶氳竟褰互瀵归綈鍧愭爣杞�
+ List<Point> rotatedPoly = new ArrayList<>();
+ for (Point p : boundary) rotatedPoly.add(rotatePoint(p, -angle));
+
+ double minY = Double.MAX_VALUE, maxY = -Double.MAX_VALUE;
+ for (Point p : rotatedPoly) {
+ minY = Math.min(minY, p.y);
+ maxY = Math.max(maxY, p.y);
+ }
+
+ // 3. 鐢熸垚鎵弿绾�
+ List<PathSegment> segments = new ArrayList<>();
+ boolean l2r = true;
+ // 鍥磋竟璺緞鍏堢敓鎴�
+ Point scanStartPoint = null;
+
+ // 杩欓噷鎴戜滑鍏堣绠楁壂鎻忕嚎锛屾渶鍚庡啀鍐冲畾鍥磋竟璧风偣浠ュ噺灏戠┖璧�
+ List<List<PathSegment>> scanRows = new ArrayList<>();
+
+ for (double y = minY + width/2; y <= maxY - width/2; y += width) {
+ List<Double> xInters = getXIntersections(rotatedPoly, y);
+ if (xInters.size() < 2) continue;
+ Collections.sort(xInters);
+
+ List<PathSegment> row = new ArrayList<>();
+ // 涓や袱閰嶅褰㈡垚绾挎
+ for (int i = 0; i < xInters.size() - 1; i += 2) {
+ Point s = rotatePoint(new Point(xInters.get(i), y), angle);
+ Point e = rotatePoint(new Point(xInters.get(i + 1), y), angle);
+ row.add(new PathSegment(s, e, true));
+ }
+
+ // 铔囧舰鎺掑簭
+ if (!l2r) {
+ Collections.reverse(row);
+ for (PathSegment s : row) {
+ Point tmp = s.start; s.start = s.end; s.end = tmp;
+ }
+ }
+ scanRows.add(row);
+ if (scanStartPoint == null && !row.isEmpty()) scanStartPoint = row.get(0).start;
+ l2r = !l2r;
+ }
+
+ // 4. 鐢熸垚鍥磋竟璺緞 (瀵归綈鍒扮涓�涓壂鎻忕偣)
+ List<Point> alignedBoundary = alignBoundaryStart(boundary, scanStartPoint);
+ for (int i = 0; i < alignedBoundary.size(); i++) {
+ segments.add(new PathSegment(alignedBoundary.get(i), alignedBoundary.get((i+1)%alignedBoundary.size()), true));
+ }
+
+ // 5. 鍔犲叆鎵弿璺緞
+ for (List<PathSegment> row : scanRows) {
+ segments.addAll(row);
+ }
+
+ return segments;
+ }
+
+ // --- 闅滅鐗╁鐞嗙被 ---
+
+ private static List<Obstacle> parseObstacles(String obsStr, double margin) {
+ List<Obstacle> list = new ArrayList<>();
+ if (obsStr == null || obsStr.trim().isEmpty()) return list;
+
+ // 澶勭悊鏍煎紡 (x,y;...)(x,y;...) 鎴� $ 鍒嗛殧
+ String cleanStr = obsStr.replaceAll("\\s+", "");
+ String[] parts;
+ if (cleanStr.contains("(") && cleanStr.contains(")")) {
+ List<String> matches = new ArrayList<>();
+ java.util.regex.Matcher m = java.util.regex.Pattern.compile("\\(([^)]+)\\)").matcher(cleanStr);
+ while (m.find()) matches.add(m.group(1));
+ parts = matches.toArray(new String[0]);
+ } else {
+ parts = cleanStr.split("\\$");
+ }
+
+ for (String pStr : parts) {
+ List<Point> pts = parseCoordinates(pStr);
+ if (pts.isEmpty()) continue;
+
+ if (pts.size() == 2) {
+ // 鍦嗗舰闅滅鐗�
+ double r = distance(pts.get(0), pts.get(1));
+ list.add(new CircleObstacle(pts.get(0), r + margin)); // 鍗婂緞澧炲姞margin
+ } else {
+ // 澶氳竟褰㈤殰纰嶇墿
+ ensureCounterClockwise(pts);
+ // 澶栨墿闅滅鐗� (Offset Out)
+ // 娉ㄦ剰锛氬湪閫氱敤鍋忕Щ绠楁硶涓紝閫嗘椂閽堝杈瑰舰锛岃礋鏁伴�氬父琛ㄧず澶栨墿锛屾垨鑰呬娇鐢ㄧ壒瀹氱畻娉�
+ // 杩欓噷鎴戜滑澶嶇敤 getOffsetPolygon锛屽苟浼犲叆璐熺殑margin鏉ュ疄鐜板鎵�
+ // *浣嗗湪鏈被鐩墠鐨� getOffsetPolygon 瀹炵幇涓紙鍩轰簬瑙掑钩鍒嗙嚎锛夛紝濡傛灉鏄�嗘椂閽堬細
+ // 姝f暟鏄悜宸︼紙鍐呯缉锛夛紝璐熸暟鏄悜鍙筹紙澶栨墿锛�*
+ List<Point> expanded = getOffsetPolygon(pts, -margin);
+ list.add(new PolyObstacle(expanded));
+ }
+ }
+ return list;
+ }
+
+ abstract static class Obstacle {
+ // 杩斿洖瑁佸壀鍚庣殑绾挎鍒楄〃锛堝嵆淇濈暀鍦ㄩ殰纰嶇墿澶栭儴鐨勭嚎娈碉級
+ abstract List<PathSegment> clip(PathSegment seg);
+ }
+
+ static class CircleObstacle extends Obstacle {
+ Point c; double r;
+ CircleObstacle(Point c, double r) { this.c = c; this.r = r; }
+
+ @Override
+ List<PathSegment> clip(PathSegment seg) {
+ // 璁$畻鐩寸嚎涓庡渾鐨勪氦鐐� t鍊� (0..1)
+ double dx = seg.end.x - seg.start.x;
+ double dy = seg.end.y - seg.start.y;
+ double fx = seg.start.x - c.x;
+ double fy = seg.start.y - c.y;
+
+ double A = dx*dx + dy*dy;
+ double B = 2*(fx*dx + fy*dy);
+ double C = (fx*fx + fy*fy) - r*r;
+ double delta = B*B - 4*A*C;
+
+ List<PathSegment> result = new ArrayList<>();
+ if (delta < 0) {
+ // 鏃犱氦鐐癸紝鍏ㄤ繚鐣欐垨鍏ㄥ墧闄�
+ if (!isInside(seg.start)) result.add(seg);
+ return result;
+ }
+
+ double t1 = (-B - Math.sqrt(delta)) / (2*A);
+ double t2 = (-B + Math.sqrt(delta)) / (2*A);
+
+ List<Double> ts = new ArrayList<>();
+ ts.add(0.0);
+ if (t1 > 0 && t1 < 1) ts.add(t1);
+ if (t2 > 0 && t2 < 1) ts.add(t2);
+ ts.add(1.0);
+ Collections.sort(ts);
+
+ for (int i = 0; i < ts.size()-1; i++) {
+ double midT = (ts.get(i) + ts.get(i+1)) / 2;
+ Point mid = interpolate(seg.start, seg.end, midT);
+ if (!isInside(mid)) {
+ result.add(new PathSegment(interpolate(seg.start, seg.end, ts.get(i)),
+ interpolate(seg.start, seg.end, ts.get(i+1)),
+ seg.isMowing));
+ }
+ }
+ return result;
+ }
+
+ boolean isInside(Point p) {
+ return (p.x-c.x)*(p.x-c.x) + (p.y-c.y)*(p.y-c.y) < r*r;
+ }
+ }
+
+ static class PolyObstacle extends Obstacle {
+ List<Point> points;
+ double minX, maxX, minY, maxY;
+
+ PolyObstacle(List<Point> pts) {
+ this.points = pts;
+ updateBounds();
+ }
+
+ void updateBounds() {
+ minX = minY = Double.MAX_VALUE;
+ maxX = maxY = -Double.MAX_VALUE;
+ for (Point p : points) {
+ minX = Math.min(minX, p.x); maxX = Math.max(maxX, p.x);
+ minY = Math.min(minY, p.y); maxY = Math.max(maxY, p.y);
+ }
+ }
+
+ boolean isInside(Point p) {
+ if (p.x < minX || p.x > maxX || p.y < minY || p.y > maxY) return false;
+ boolean result = false;
+ for (int i = 0, j = points.size() - 1; i < points.size(); j = i++) {
+ if ((points.get(i).y > p.y) != (points.get(j).y > p.y) &&
+ (p.x < (points.get(j).x - points.get(i).x) * (p.y - points.get(i).y) / (points.get(j).y - points.get(i).y) + points.get(i).x)) {
+ result = !result;
+ }
+ }
+ return result;
+ }
+
+ @Override
+ List<PathSegment> clip(PathSegment seg) {
+ List<Double> ts = new ArrayList<>();
+ ts.add(0.0);
+ ts.add(1.0);
+
+ // 璁$畻绾挎涓庨殰纰嶇墿姣忎竴鏉¤竟鐨勪氦鐐�
+ for (int i = 0; i < points.size(); i++) {
+ Point p1 = points.get(i);
+ Point p2 = points.get((i+1)%points.size());
+ double t = getIntersectionT(seg.start, seg.end, p1, p2);
+ if (t > 1e-6 && t < 1 - 1e-6) {
+ ts.add(t);
+ }
+ }
+ Collections.sort(ts);
+
+ List<PathSegment> result = new ArrayList<>();
+ // 妫�鏌ユ瘡涓�灏忔鐨勪腑鐐规槸鍚﹀湪闅滅鐗╁唴
+ for (int i = 0; i < ts.size() - 1; i++) {
+ double tMid = (ts.get(i) + ts.get(i+1)) / 2.0;
+ // 濡傛灉涓ょ偣鏋佸叾鎺ヨ繎锛岃烦杩�
+ if (ts.get(i+1) - ts.get(i) < 1e-6) continue;
+
+ Point mid = interpolate(seg.start, seg.end, tMid);
+ if (!isInside(mid)) {
+ // 鍦ㄥ閮紝淇濈暀
+ Point s = interpolate(seg.start, seg.end, ts.get(i));
+ Point e = interpolate(seg.start, seg.end, ts.get(i+1));
+ result.add(new PathSegment(s, e, seg.isMowing));
+ }
+ }
+ return result;
+ }
+ }
+
+ // --- 閫氱敤鍑犱綍绠楁硶 ---
+
private static List<Point> getOffsetPolygon(List<Point> points, double offset) {
List<Point> result = new ArrayList<>();
int n = points.size();
@@ -83,208 +322,67 @@
Point p2 = points.get(i);
Point p3 = points.get((i + 1) % n);
+ // 鍚戦噺 p1->p2 鍜� p2->p3
double v1x = p2.x - p1.x, v1y = p2.y - p1.y;
double v2x = p3.x - p2.x, v2y = p3.y - p2.y;
double l1 = Math.hypot(v1x, v1y), l2 = Math.hypot(v2x, v2y);
- if (l1 < 1e-6 || l2 < 1e-6) continue;
+ if (l1 < 1e-5 || l2 < 1e-5) continue;
- // 鑾峰彇涓ゆ潯杈圭殑娉曞悜閲忥紙鍚戝乏鍋忕Щ锛�
+ // 娉曞悜閲� (鍚戝乏杞�90搴�: -y, x)
double n1x = -v1y / l1, n1y = v1x / l1;
double n2x = -v2y / l2, n2y = v2x / l2;
- // 瑙掑钩鍒嗙嚎鍚戦噺
+ // 瑙掑钩鍒嗙嚎
double bx = n1x + n2x, by = n1y + n2y;
double bl = Math.hypot(bx, by);
- if (bl < 1e-6) {
- bx = n1x; by = n1y;
- } else {
- bx /= bl; by /= bl;
- }
+ if (bl < 1e-5) { bx = n1x; by = n1y; }
+ else { bx /= bl; by /= bl; }
- // 璁$畻鍋忕Щ闀垮害淇绯绘暟锛�1/sin(theta/2)
- double cosHalf = n1x * bx + n1y * by;
- double d = offset / Math.max(cosHalf, 0.1); // 閬垮厤鍒嗘瘝杩囧皬瀵艰嚧鏃犵┓澶�
+ // 淇闀垮害 offset / sin(theta/2) = offset / dot(n1, b)
+ double dot = n1x * bx + n1y * by;
+ double dist = offset / Math.max(Math.abs(dot), 0.1); // 闃叉灏栬杩囬暱
- // 闄愬埗鏈�澶т綅绉婚噺锛岄槻姝㈡瀬灏栬鐣稿彉
- d = Math.signum(offset) * Math.min(Math.abs(d), Math.abs(offset) * 5);
+ // 闃堝�奸檺鍒讹紝闃叉鑷氦鎴栫暩鍙樿繃澶�
+ dist = Math.signum(offset) * Math.min(Math.abs(dist), Math.abs(offset) * 3);
- result.add(new Point(p2.x + bx * d, p2.y + by * d));
+ result.add(new Point(p2.x + bx * dist, p2.y + by * dist));
}
return result;
}
- private static List<PathSegment> optimizeAndClipPath(List<PathSegment> originalPath, List<Obstacle> obstacles) {
- List<PathSegment> result = new ArrayList<>();
- Point currentPos = null;
-
- for (PathSegment segment : originalPath) {
- List<PathSegment> clipped = new ArrayList<>();
- clipped.add(segment);
-
- // 鐢ㄦ瘡涓�涓殰纰嶇墿渚濇瑁佸壀
- for (Obstacle obs : obstacles) {
- List<PathSegment> nextIter = new ArrayList<>();
- for (PathSegment s : clipped) {
- nextIter.addAll(obs.clipSegment(s));
- }
- clipped = nextIter;
- }
-
- for (PathSegment s : clipped) {
- // 鍓旈櫎寰皬娈�
- if (Math.hypot(s.start.x - s.end.x, s.start.y - s.end.y) < 1e-4) continue;
-
- // 濡傛灉鏂版鐨勮捣鐐逛笌涓婃鐨勭粓鐐逛笉杩炶疮锛屾坊鍔犵┖璧帮紙闈炲壊鑽夛級璺緞
- if (currentPos != null && Math.hypot(currentPos.x - s.start.x, currentPos.y - s.start.y) > 0.01) {
- result.add(new PathSegment(currentPos, s.start, false));
- }
- result.add(s);
- currentPos = s.end;
- }
+ private static double findOptimalAngle(List<Point> poly) {
+ double bestA = 0, minH = Double.MAX_VALUE;
+ for (int i = 0; i < poly.size(); i++) {
+ Point p1 = poly.get(i), p2 = poly.get((i + 1) % poly.size());
+ double a = Math.atan2(p2.y - p1.y, p2.x - p1.x);
+ double h = calcHeight(poly, a);
+ if (h < minH) { minH = h; bestA = a; }
}
- return result;
+ return bestA;
}
- // --- 闅滅鐗╃被瀹氫箟 ---
- abstract static class Obstacle {
- abstract boolean isInside(Point p);
- abstract List<PathSegment> clipSegment(PathSegment seg);
- }
-
- static class PolyObstacle extends Obstacle {
- List<Point> points;
- double minX, maxX, minY, maxY;
-
- public PolyObstacle(List<Point> pts) {
- this.points = pts;
- minX = minY = Double.MAX_VALUE;
- maxX = maxY = -Double.MAX_VALUE;
- for (Point p : pts) {
- minX = Math.min(minX, p.x); maxX = Math.max(maxX, p.x);
- minY = Math.min(minY, p.y); maxY = Math.max(maxY, p.y);
- }
+ private static double calcHeight(List<Point> poly, double ang) {
+ double min = Double.MAX_VALUE, max = -Double.MAX_VALUE;
+ for (Point p : poly) {
+ Point r = rotatePoint(p, -ang);
+ min = Math.min(min, r.y); max = Math.max(max, r.y);
}
-
- @Override
- boolean isInside(Point p) {
- if (p.x < minX || p.x > maxX || p.y < minY || p.y > maxY) return false;
- boolean inside = false;
- for (int i = 0, j = points.size() - 1; i < points.size(); j = i++) {
- if (((points.get(i).y > p.y) != (points.get(j).y > p.y)) &&
- (p.x < (points.get(j).x - points.get(i).x) * (p.y - points.get(i).y) / (points.get(j).y - points.get(i).y) + points.get(i).x)) {
- inside = !inside;
- }
- }
- return inside;
- }
-
- @Override
- List<PathSegment> clipSegment(PathSegment seg) {
- List<Double> ts = new ArrayList<>(Arrays.asList(0.0, 1.0));
- for (int i = 0; i < points.size(); i++) {
- double t = getIntersectionT(seg.start, seg.end, points.get(i), points.get((i + 1) % points.size()));
- if (t > 0 && t < 1) ts.add(t);
- }
- Collections.sort(ts);
- List<PathSegment> res = new ArrayList<>();
- for (int i = 0; i < ts.size() - 1; i++) {
- Point s = interpolate(seg.start, seg.end, ts.get(i));
- Point e = interpolate(seg.start, seg.end, ts.get(i + 1));
- // 妫�鏌ヤ腑鐐规槸鍚﹀湪闅滅鐗╁唴
- if (!isInside(new Point((s.x + e.x) / 2, (s.y + e.y) / 2))) {
- res.add(new PathSegment(s, e, seg.isMowing));
- }
- }
- return res;
- }
- }
-
- static class CircleObstacle extends Obstacle {
- Point center; double radius;
- public CircleObstacle(Point c, double r) { this.center = c; this.radius = r; }
-
- @Override
- boolean isInside(Point p) { return Math.hypot(p.x - center.x, p.y - center.y) < radius - 1e-4; }
-
- @Override
- List<PathSegment> clipSegment(PathSegment seg) {
- List<Double> ts = new ArrayList<>(Arrays.asList(0.0, 1.0));
- double dx = seg.end.x - seg.start.x, dy = seg.end.y - seg.start.y;
- double fx = seg.start.x - center.x, fy = seg.start.y - center.y;
- double a = dx * dx + dy * dy;
- double b = 2 * (fx * dx + fy * dy);
- double c = fx * fx + fy * fy - radius * radius;
- double disc = b * b - 4 * a * c;
- if (disc >= 0) {
- disc = Math.sqrt(disc);
- double t1 = (-b - disc) / (2 * a), t2 = (-b + disc) / (2 * a);
- if (t1 > 0 && t1 < 1) ts.add(t1);
- if (t2 > 0 && t2 < 1) ts.add(t2);
- }
- Collections.sort(ts);
- List<PathSegment> res = new ArrayList<>();
- for (int i = 0; i < ts.size() - 1; i++) {
- Point s = interpolate(seg.start, seg.end, ts.get(i));
- Point e = interpolate(seg.start, seg.end, ts.get(i + 1));
- if (!isInside(new Point((s.x + e.x) / 2, (s.y + e.y) / 2))) res.add(new PathSegment(s, e, seg.isMowing));
- }
- return res;
- }
- }
-
- // --- 鍐呴儴绠楁硶涓庢暟瀛︽敮鎸� ---
-
- private static List<PathSegment> generateGlobalScanPath(List<Point> polygon, double width, double angle, Point currentPos) {
- List<PathSegment> segments = new ArrayList<>();
- List<Point> rotated = new ArrayList<>();
- for (Point p : polygon) rotated.add(rotatePoint(p, -angle));
-
- double minY = Double.MAX_VALUE, maxY = -Double.MAX_VALUE;
- for (Point p : rotated) { minY = Math.min(minY, p.y); maxY = Math.max(maxY, p.y); }
-
- boolean l2r = true;
- for (double y = minY + width/2; y <= maxY - width/2; y += width) {
- List<Double> xInters = getXIntersections(rotated, y);
- if (xInters.size() < 2) continue;
- Collections.sort(xInters);
-
- List<PathSegment> row = new ArrayList<>();
- for (int i = 0; i < xInters.size() - 1; i += 2) {
- Point s = rotatePoint(new Point(xInters.get(i), y), angle);
- Point e = rotatePoint(new Point(xInters.get(i + 1), y), angle);
- row.add(new PathSegment(s, e, true));
- }
- if (!l2r) {
- Collections.reverse(row);
- for (PathSegment s : row) { Point t = s.start; s.start = s.end; s.end = t; }
- }
- for (PathSegment s : row) {
- if (Math.hypot(currentPos.x - s.start.x, currentPos.y - s.start.y) > 0.01) {
- segments.add(new PathSegment(currentPos, s.start, false));
- }
- segments.add(s);
- currentPos = s.end;
- }
- l2r = !l2r;
- }
- return segments;
+ return max - min;
}
private static double getIntersectionT(Point a, Point b, Point c, Point d) {
- double ux = b.x - a.x, uy = b.y - a.y, vx = d.x - c.x, vy = d.y - c.y;
+ double ux = b.x - a.x, uy = b.y - a.y;
+ double vx = d.x - c.x, vy = d.y - c.y;
double det = vx * uy - vy * ux;
- if (Math.abs(det) < 1e-6) return -1;
- return (vx * (c.y - a.y) - vy * (c.x - a.x)) / det;
- }
-
- private static Point interpolate(Point a, Point b, double t) {
- return new Point(a.x + (b.x - a.x) * t, a.y + (b.y - a.y) * t);
- }
-
- private static Point rotatePoint(Point p, double ang) {
- double cos = Math.cos(ang), sin = Math.sin(ang);
- return new Point(p.x * cos - p.y * sin, p.x * sin + p.y * cos);
+ if (Math.abs(det) < 1e-8) return -1;
+
+ double wx = c.x - a.x, wy = c.y - a.y;
+ double t = (vx * wy - vy * wx) / det;
+ double u = (ux * wy - uy * wx) / det;
+
+ if (u >= 0 && u <= 1) return t; // 鍙繚璇佷氦鐐瑰湪绾挎CD涓婏紝t鏄疉B涓婄殑姣斾緥
+ return -1;
}
private static List<Double> getXIntersections(List<Point> poly, double y) {
@@ -298,21 +396,11 @@
return res;
}
- private static Point getFirstScanPoint(List<Point> poly, double w, double a) {
- List<Point> rot = new ArrayList<>();
- for (Point p : poly) rot.add(rotatePoint(p, -a));
- double minY = Double.MAX_VALUE;
- for (Point p : rot) minY = Math.min(minY, p.y);
- List<Double> xs = getXIntersections(rot, minY + w/2);
- if (xs.isEmpty()) return poly.get(0);
- Collections.sort(xs);
- return rotatePoint(new Point(xs.get(0), minY + w/2), a);
- }
-
private static List<Point> alignBoundaryStart(List<Point> poly, Point target) {
+ if (target == null) return poly;
int idx = 0; double minD = Double.MAX_VALUE;
for (int i = 0; i < poly.size(); i++) {
- double d = Math.hypot(poly.get(i).x - target.x, poly.get(i).y - target.y);
+ double d = distance(poly.get(i), target);
if (d < minD) { minD = d; idx = i; }
}
List<Point> res = new ArrayList<>();
@@ -320,28 +408,27 @@
return res;
}
- private static double findOptimalAngle(List<Point> poly) {
- double bestA = 0, minH = Double.MAX_VALUE;
- for (int i = 0; i < poly.size(); i++) {
- Point p1 = poly.get(i), p2 = poly.get((i + 1) % poly.size());
- double a = Math.atan2(p2.y - p1.y, p2.x - p1.x);
- double miY = Double.MAX_VALUE, maY = -Double.MAX_VALUE;
- for (Point p : poly) {
- Point r = rotatePoint(p, -a);
- miY = Math.min(miY, r.y); maY = Math.max(maY, r.y);
- }
- if (maY - miY < minH) { minH = maY - miY; bestA = a; }
- }
- return bestA;
- }
-
private static void ensureCounterClockwise(List<Point> pts) {
double s = 0;
for (int i = 0; i < pts.size(); i++) {
Point p1 = pts.get(i), p2 = pts.get((i + 1) % pts.size());
s += (p2.x - p1.x) * (p2.y + p1.y);
}
- if (s > 0) Collections.reverse(pts);
+ if (s > 0) Collections.reverse(pts); // 鍋囪灞忓箷鍧愭爣绯籝鍚戜笅锛熼�氬父澶氳竟褰㈤潰绉叕寮弒>0鏄『鏃堕拡(Y鍚戜笅)鎴栭�嗘椂閽�(Y鍚戜笂)
+ // 姝ゅ娌跨敤鎮ㄤ唬鐮佺殑閫昏緫锛氬鏋淪um>0 鍒欏弽杞��
+ }
+
+ private static Point rotatePoint(Point p, double a) {
+ double c = Math.cos(a), s = Math.sin(a);
+ return new Point(p.x * c - p.y * s, p.x * s + p.y * c);
+ }
+
+ private static Point interpolate(Point a, Point b, double t) {
+ return new Point(a.x + (b.x - a.x) * t, a.y + (b.y - a.y) * t);
+ }
+
+ private static double distance(Point a, Point b) {
+ return Math.hypot(a.x - b.x, a.y - b.y);
}
private static List<Point> parseCoordinates(String s) {
@@ -349,26 +436,23 @@
if (s == null || s.isEmpty()) return pts;
for (String p : s.split(";")) {
String[] xy = p.split(",");
- if (xy.length == 2) pts.add(new Point(Double.parseDouble(xy[0]), Double.parseDouble(xy[1])));
+ if (xy.length >= 2) pts.add(new Point(Double.parseDouble(xy[0]), Double.parseDouble(xy[1])));
}
- if (pts.size() > 1 && pts.get(0).equals(pts.get(pts.size() - 1))) pts.remove(pts.size() - 1);
+ if (pts.size() > 1 && distance(pts.get(0), pts.get(pts.size() - 1)) < 1e-4) pts.remove(pts.size() - 1);
return pts;
}
+ // --- 鏁版嵁缁撴瀯 ---
public static class Point {
public double x, y;
public Point(double x, double y) { this.x = x; this.y = y; }
- @Override
- public boolean equals(Object o) {
- if (!(o instanceof Point)) return false;
- Point p = (Point) o;
- return Math.abs(x - p.x) < 1e-4 && Math.abs(y - p.y) < 1e-4;
- }
}
public static class PathSegment {
public Point start, end;
public boolean isMowing;
public PathSegment(Point s, Point e, boolean m) { this.start = s; this.end = e; this.isMowing = m; }
+ @Override
+ public String toString() { return String.format("%.6f,%.6f;%.6f,%.6f", start.x, start.y, end.x, end.y); }
}
}
\ No newline at end of file
diff --git a/src/sendMQTT/HTTPUtils/FileUploadResponse.java b/src/sendMQTT/HTTPUtils/FileUploadResponse.java
new file mode 100644
index 0000000..8a58825
--- /dev/null
+++ b/src/sendMQTT/HTTPUtils/FileUploadResponse.java
@@ -0,0 +1,111 @@
+package sendMQTT.HTTPUtils;
+
+import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
+import com.fasterxml.jackson.annotation.JsonProperty;
+import lombok.Data;
+
+/**
+ * 鏂囦欢涓婁紶鍝嶅簲缁撴灉绫�
+ * 瀵瑰簲鎺ュ彛鏂囨。涓殑鍝嶅簲鏍煎紡
+ */
+
+@JsonIgnoreProperties(ignoreUnknown = true) // 蹇界暐鏈煡瀛楁锛屾彁楂樺吋瀹规��
+public class FileUploadResponse {
+
+ private String uuid;
+ private String filename;
+
+ @JsonProperty("savedFilename")
+ private String savedFilename;
+
+ @JsonProperty("downloadUrl")
+ private String downloadUrl;
+
+ private String message;
+
+ @JsonProperty("fileType")
+ private String fileType;
+
+ private String size; // 鏂囦欢澶у皬
+
+ @JsonProperty("hexString")
+ private String hexString; // 鍗佸叚杩涘埗瀛楃涓�
+
+ public FileUploadResponse() {
+ }
+
+ public FileUploadResponse(String uuid, String filename, String savedFilename,
+ String downloadUrl, String message, String fileType) {
+ this.uuid = uuid;
+ this.filename = filename;
+ this.savedFilename = savedFilename;
+ this.downloadUrl = downloadUrl;
+ this.message = message;
+ this.fileType = fileType;
+ }
+
+ public String getUuid() {
+ return uuid;
+ }
+
+ public void setUuid(String uuid) {
+ this.uuid = uuid;
+ }
+
+ public String getFilename() {
+ return filename;
+ }
+
+ public void setFilename(String filename) {
+ this.filename = filename;
+ }
+
+ public String getSavedFilename() {
+ return savedFilename;
+ }
+
+ public void setSavedFilename(String savedFilename) {
+ this.savedFilename = savedFilename;
+ }
+
+ public String getDownloadUrl() {
+ return downloadUrl;
+ }
+
+ public void setDownloadUrl(String downloadUrl) {
+ this.downloadUrl = downloadUrl;
+ }
+
+ public String getMessage() {
+ return message;
+ }
+
+ public void setMessage(String message) {
+ this.message = message;
+ }
+
+ public String getFileType() {
+ return fileType;
+ }
+
+ public void setFileType(String fileType) {
+ this.fileType = fileType;
+ }
+
+ public String getSize() {
+ return size;
+ }
+
+ public void setSize(String size) {
+ this.size = size;
+ }
+
+ public String getHexString() {
+ return hexString;
+ }
+
+ public void setHexString(String hexString) {
+ this.hexString = hexString;
+ }
+}
+
diff --git a/src/sendMQTT/HTTPUtils/MovePathCommand.java b/src/sendMQTT/HTTPUtils/MovePathCommand.java
new file mode 100644
index 0000000..10d3c87
--- /dev/null
+++ b/src/sendMQTT/HTTPUtils/MovePathCommand.java
@@ -0,0 +1,58 @@
+package sendMQTT.HTTPUtils;
+
+import com.fasterxml.jackson.annotation.JsonProperty;
+import lombok.Data;
+
+/**
+ * 绉诲姩璺緞鍛戒护JSON缁撴瀯
+ */
+@Data
+public class MovePathCommand {
+
+ @JsonProperty("msg_id")
+ private String msgId;
+
+ private long timestamp;
+
+ @JsonProperty("user_id")
+ private String userId;
+
+ @JsonProperty("device_id")
+ private String deviceId;
+
+ private String command;
+
+ private MovePathData data;
+
+ public MovePathCommand() {
+ }
+
+ public MovePathCommand(String msgId, long timestamp, String userId, String deviceId, MovePathData data) {
+ this.msgId = msgId;
+ this.timestamp = timestamp;
+ this.userId = userId;
+ this.deviceId = deviceId;
+ this.command = "movePath";
+ this.data = data;
+ }
+
+ /**
+ * 鏁版嵁鍐呴儴绫�
+ */
+ @Data
+ public static class MovePathData {
+ private String filename;
+ private String filesize;
+ private String url;
+
+ public MovePathData() {
+ }
+
+ public MovePathData(String filename, String filesize, String url) {
+ this.filename = filename;
+ this.filesize = filesize;
+ this.url = url;
+ }
+ }
+}
+
diff --git a/src/sendMQTT/HTTPUtils/PropertiesFileUploader.java b/src/sendMQTT/HTTPUtils/PropertiesFileUploader.java
new file mode 100644
index 0000000..80d8576
--- /dev/null
+++ b/src/sendMQTT/HTTPUtils/PropertiesFileUploader.java
@@ -0,0 +1,337 @@
+package sendMQTT.HTTPUtils;
+
+import com.fasterxml.jackson.core.JsonProcessingException;
+import com.fasterxml.jackson.databind.ObjectMapper;
+
+import java.io.*;
+import java.net.HttpURLConnection;
+import java.net.URL;
+import java.net.URLEncoder;
+import java.nio.charset.StandardCharsets;
+import java.util.Properties;
+
+/**
+ * Properties鏂囦欢涓婁紶宸ュ叿绫�
+ * 灏哖roperties鏂囦欢杞崲涓篔SON骞朵笂浼犲埌鏈嶅姟鍣�
+ */
+public class PropertiesFileUploader {
+
+ private static final String DEFAULT_UPLOAD_URL = "http://39.99.43.227:8866/api/file/upload";
+ private static final String DEFAULT_FILENAME = "dikuai";
+ private static final int CONNECT_TIMEOUT = 30000; // 30绉掕繛鎺ヨ秴鏃�
+ private static final int READ_TIMEOUT = 60000; // 60绉掕鍙栬秴鏃�
+
+
+ /**
+ * 灏哖roperties鏂囦欢杞崲涓篔SON瀛楃涓�
+ * @param filePath Properties鏂囦欢璺緞
+ * @return JSON瀛楃涓�
+ * @throws Exception 濡傛灉璇诲彇鎴栬浆鎹㈠け璐�
+ */
+ public static String propertiesFileToJson(String filePath) throws Exception {
+ Properties props = new Properties();
+ InputStream inputStream = null;
+
+ try {
+ File file = new File(filePath);
+ if (!file.exists() || !file.isFile()) {
+ throw new Exception("鏂囦欢涓嶅瓨鍦ㄦ垨涓嶆槸鏈夋晥鏂囦欢: " + filePath);
+ }
+
+ inputStream = new FileInputStream(file);
+ props.load(inputStream);
+
+ // 浣跨敤Jackson灏哖roperties杞崲涓篔SON瀛楃涓�
+ ObjectMapper objectMapper = new ObjectMapper();
+ // Properties鏈川涓婃槸涓�涓狹ap<String, String>锛屽彲浠ョ洿鎺ュ簭鍒楀寲涓篔SON
+ String json = objectMapper.writeValueAsString(props);
+
+ return json;
+ } finally {
+ if (inputStream != null) {
+ inputStream.close();
+ }
+ }
+ }
+
+ /**
+ * 鐢熸垚姣绾ф椂闂存埑
+ * @return 褰撳墠鏃堕棿鐨勬绉掔骇鏃堕棿鎴筹紙鑷�1970骞�1鏈�1鏃TC浠ユ潵鐨勬绉掓暟锛�
+ */
+ public static long getCurrentTimestamp() {
+ return System.currentTimeMillis();
+ }
+
+ /**
+ * 绉诲姩璺緞鍙戦�佹柟娉�
+ *
+ * @param mes_id 娑堟伅鍞竴鏍囪瘑
+ * @param user_id 鐢ㄦ埛ID
+ * @param device_id 璁惧缂栧彿
+ * @param propertiesFilePath Properties鏂囦欢璺緞
+ * @return JSON瀛楃涓�
+ * @throws Exception 褰撲笂浼犳垨杞崲澶辫触鏃舵姏鍑�
+ */
+ public static String movePathSend(String mes_id, String user_id, String device_id, String propertiesFilePath) {
+ // 涓婁紶Properties鏂囦欢
+ FileUploadResponse fileUploadResponse = PropertiesFileUploader.uploadPropertiesFile(propertiesFilePath);
+ if (fileUploadResponse == null) {
+ return null;
+ }
+
+/* // 鎵撳嵃涓婁紶鍝嶅簲淇℃伅
+ System.out.println("鏂囦欢涓婁紶鍝嶅簲淇℃伅锛�");
+ System.out.println("鈹溾攢 娑堟伅鍐呭: " + fileUploadResponse.getMessage());
+ System.out.println("鈹溾攢 鍘熷鏂囦欢鍚�: " + fileUploadResponse.getFilename());
+ System.out.println("鈹溾攢 淇濆瓨鏂囦欢鍚�: " + fileUploadResponse.getSavedFilename());
+ System.out.println("鈹溾攢 鏂囦欢绫诲瀷: " + fileUploadResponse.getFileType());
+ System.out.println("鈹溾攢 鏂囦欢澶у皬: " + fileUploadResponse.getSize());
+ System.out.println("鈹溾攢 涓嬭浇鍦板潃: " + fileUploadResponse.getDownloadUrl());
+ System.out.println("鈹溾攢 鏂囦欢UUID: " + fileUploadResponse.getUuid());
+ System.out.println("鈹斺攢 鏂囦欢鍝堝笇: " + (fileUploadResponse.getHexString() != null ? fileUploadResponse.getHexString() : "N/A"));*/
+
+ // 鏋勫缓鏁版嵁瀵硅薄
+ MovePathCommand.MovePathData pathData = new MovePathCommand.MovePathData(
+ fileUploadResponse.getSavedFilename(), // filename
+ fileUploadResponse.getSize(), // filesize
+ fileUploadResponse.getDownloadUrl() // url
+ );
+ long timestamp = PropertiesFileUploader.getCurrentTimestamp();
+ // 鏋勫缓鍛戒护瀵硅薄
+ MovePathCommand command = new MovePathCommand(
+ mes_id,
+ timestamp,
+ user_id,
+ device_id,
+ pathData
+ );
+
+ // 杞崲涓篔SON瀛楃涓�
+ ObjectMapper objectMapper = new ObjectMapper();
+ String jsonString = null;
+ try {
+ jsonString = objectMapper.writerWithDefaultPrettyPrinter().writeValueAsString(command);
+ } catch (JsonProcessingException e) {
+ return null;
+ }
+
+ return jsonString;
+ }
+
+
+
+
+ /**
+ * 涓婁紶Properties鏂囦欢鍒版湇鍔″櫒
+ *
+ * @param filePath Properties鏂囦欢璺緞
+ * @param filename 鏂囦欢鍚嶏紙鐢ㄤ簬URL鍙傛暟锛岄粯璁や负"dikuai"锛�
+ * @param uploadUrl 涓婁紶鎺ュ彛URL锛堝彲閫夛紝榛樿浣跨敤鏂囨。涓殑URL锛�
+ * @return FileUploadResponse 涓婁紶鍝嶅簲缁撴灉
+ * @throws Exception 褰撲笂浼犲け璐ユ椂鎶涘嚭
+ */
+ public static FileUploadResponse uploadPropertiesFile(String filePath, String filename, String uploadUrl) throws Exception {
+ // 鍙傛暟鏍¢獙
+ if (filePath == null || filePath.trim().isEmpty()) {
+ throw new IllegalArgumentException("鏂囦欢璺緞涓嶈兘涓虹┖");
+ }
+
+ // 浣跨敤榛樿鍊�
+ if (filename == null || filename.trim().isEmpty()) {
+ filename = DEFAULT_FILENAME;
+ }
+ if (uploadUrl == null || uploadUrl.trim().isEmpty()) {
+ uploadUrl = DEFAULT_UPLOAD_URL;
+ }
+
+ // 璋冪敤Server.propertiesFileToJson鏂规硶鐢熸垚JSON瀛楃涓�
+ String jsonData = propertiesFileToJson(filePath);
+ System.out.println("宸叉垚鍔熷皢Properties鏂囦欢杞崲涓篔SON: " + filePath);
+
+ // 鏋勫缓瀹屾暣鐨刄RL锛堝寘鍚玣ilename鍙傛暟锛岃繘琛孶RL缂栫爜锛�
+ String encodedFilename = URLEncoder.encode(filename, StandardCharsets.UTF_8.name());
+ String fullUrl = uploadUrl + "?filename=" + encodedFilename;
+
+ // 鍙戦�丠TTP POST璇锋眰
+ HttpURLConnection connection = createConnection(fullUrl);
+
+ try {
+ // 鍙戦�丣SON鏁版嵁
+ try (OutputStream outputStream = connection.getOutputStream()) {
+ byte[] jsonBytes = jsonData.getBytes(StandardCharsets.UTF_8);
+ outputStream.write(jsonBytes);
+ outputStream.flush();
+ }
+
+ // 鑾峰彇鍝嶅簲
+ String responseJson = getResponse(connection);
+
+ // 瑙f瀽鍝嶅簲JSON
+ ObjectMapper objectMapper = new ObjectMapper();
+ FileUploadResponse response = objectMapper.readValue(responseJson, FileUploadResponse.class);
+
+ System.out.println("鏂囦欢涓婁紶鎴愬姛: " + response.getSavedFilename());
+ return response;
+
+ } finally {
+ if (connection != null) {
+ connection.disconnect();
+ }
+ }
+ }
+
+ /**
+ * 涓婁紶Properties鏂囦欢鍒版湇鍔″櫒锛堜娇鐢ㄩ粯璁ゅ弬鏁帮級
+ *
+ * @param filePath Properties鏂囦欢璺緞
+ * @return FileUploadResponse 涓婁紶鍝嶅簲缁撴灉
+ * @throws Exception 褰撲笂浼犲け璐ユ椂鎶涘嚭
+ */
+ public static FileUploadResponse uploadPropertiesFile(String filePath) {
+ try {
+ return uploadPropertiesFile(filePath, DEFAULT_FILENAME, DEFAULT_UPLOAD_URL);
+ } catch (Exception e) {
+ return null;
+ }
+ }
+
+ /**
+ * 涓婁紶Properties鏂囦欢鍒版湇鍔″櫒锛堟寚瀹氭枃浠跺悕锛�
+ *
+ * @param filePath Properties鏂囦欢璺緞
+ * @param filename 鏂囦欢鍚嶏紙鐢ㄤ簬URL鍙傛暟锛�
+ * @return FileUploadResponse 涓婁紶鍝嶅簲缁撴灉
+ * @throws Exception 褰撲笂浼犲け璐ユ椂鎶涘嚭
+ */
+ public static FileUploadResponse uploadPropertiesFile(String filePath, String filename) throws Exception {
+ return uploadPropertiesFile(filePath, filename, DEFAULT_UPLOAD_URL);
+ }
+
+ /**
+ * 鍒涘缓HTTP杩炴帴
+ */
+ private static HttpURLConnection createConnection(String urlString) throws Exception {
+ URL url = new URL(urlString);
+ HttpURLConnection connection = (HttpURLConnection) url.openConnection();
+
+ // 璁剧疆杩炴帴灞炴��
+ connection.setDoOutput(true);
+ connection.setDoInput(true);
+ connection.setUseCaches(false);
+ connection.setRequestMethod("POST");
+ connection.setConnectTimeout(CONNECT_TIMEOUT);
+ connection.setReadTimeout(READ_TIMEOUT);
+
+ // 璁剧疆璇锋眰澶�
+ connection.setRequestProperty("Content-Type", "application/json; charset=UTF-8");
+ connection.setRequestProperty("Accept", "application/json");
+ connection.setRequestProperty("User-Agent", "PropertiesFileUploader/1.0");
+
+ return connection;
+ }
+
+ /**
+ * 鑾峰彇鏈嶅姟鍣ㄥ搷搴�
+ */
+ private static String getResponse(HttpURLConnection connection) throws Exception {
+ // 妫�鏌TTP鍝嶅簲鐮�
+ int status = connection.getResponseCode();
+ InputStream inputStream;
+
+ if (status >= 200 && status < 300) {
+ inputStream = connection.getInputStream();
+ } else {
+ inputStream = connection.getErrorStream();
+ }
+
+ // 璇诲彇鍝嶅簲鍐呭
+ StringBuilder response = new StringBuilder();
+ try (BufferedReader reader = new BufferedReader(
+ new InputStreamReader(inputStream, StandardCharsets.UTF_8))) {
+ String line;
+ while ((line = reader.readLine()) != null) {
+ response.append(line);
+ }
+ }
+
+ // 濡傛灉璇锋眰澶辫触锛屾姏鍑哄紓甯�
+ if (status >= 400) {
+ throw new Exception("HTTP璇锋眰澶辫触锛岀姸鎬佺爜: " + status + "锛屽搷搴�: " + response.toString());
+ }
+
+ return response.toString();
+ }
+
+ /**
+ * 瀹夊叏涓婁紶鏂规硶锛堜笉鎶涘嚭寮傚父锛岃繑鍥炵粨鏋滃璞★級
+ *
+ * @param filePath Properties鏂囦欢璺緞
+ * @param filename 鏂囦欢鍚嶏紙鐢ㄤ簬URL鍙傛暟锛屽彲閫夛級
+ * @param uploadUrl 涓婁紶鎺ュ彛URL锛堝彲閫夛級
+ * @return UploadResult 鍖呭惈涓婁紶缁撴灉鐨勫皝瑁呭璞�
+ */
+ public static UploadResult uploadPropertiesFileSafe(String filePath, String filename, String uploadUrl) {
+ try {
+ FileUploadResponse response = uploadPropertiesFile(filePath, filename, uploadUrl);
+ ObjectMapper objectMapper = new ObjectMapper();
+ String responseJson = objectMapper.writeValueAsString(response);
+ return new UploadResult(true, response.getMessage(), responseJson, 200);
+ } catch (Exception e) {
+ return new UploadResult(false, "涓婁紶澶辫触: " + e.getMessage(), null, 500);
+ }
+ }
+
+ /**
+ * 瀹夊叏涓婁紶鏂规硶锛堜娇鐢ㄩ粯璁ゅ弬鏁帮級
+ *
+ * @param filePath Properties鏂囦欢璺緞
+ * @return UploadResult 鍖呭惈涓婁紶缁撴灉鐨勫皝瑁呭璞�
+ */
+ public static UploadResult uploadPropertiesFileSafe(String filePath) {
+ return uploadPropertiesFileSafe(filePath, DEFAULT_FILENAME, DEFAULT_UPLOAD_URL);
+ }
+
+ /**
+ * 涓婁紶缁撴灉灏佽绫�
+ */
+ public static class UploadResult {
+ private boolean success;
+ private String message;
+ private String data;
+ private int statusCode;
+
+ public UploadResult(boolean success, String message, String data, int statusCode) {
+ this.success = success;
+ this.message = message;
+ this.data = data;
+ this.statusCode = statusCode;
+ }
+
+ public boolean isSuccess() {
+ return success;
+ }
+
+ public String getMessage() {
+ return message;
+ }
+
+ public String getData() {
+ return data;
+ }
+
+ public int getStatusCode() {
+ return statusCode;
+ }
+
+ @Override
+ public String toString() {
+ return "UploadResult{" +
+ "success=" + success +
+ ", message='" + message + '\'' +
+ ", data='" + data + '\'' +
+ ", statusCode=" + statusCode +
+ '}';
+ }
+ }
+}
+
diff --git a/src/sendMQTT/Server.java b/src/sendMQTT/Server.java
new file mode 100644
index 0000000..8520ab3
--- /dev/null
+++ b/src/sendMQTT/Server.java
@@ -0,0 +1,82 @@
+package sendMQTT;
+
+
+
+import java.io.UnsupportedEncodingException;
+import java.time.LocalDateTime;
+import java.time.format.DateTimeFormatter;
+import sendMQTT.HTTPUtils.PropertiesFileUploader;
+import set.Setsys;
+import user.Usrdell;
+
+import org.eclipse.paho.client.mqttv3.MqttClient;
+import org.eclipse.paho.client.mqttv3.MqttConnectOptions;
+import org.eclipse.paho.client.mqttv3.MqttException;
+import org.eclipse.paho.client.mqttv3.MqttMessage;
+
+
+public class Server {
+ static String host="tcp://39.99.43.227:1883";
+ static String clientId="1231@qq.com";
+
+ /**
+ * 鑾峰彇褰撳墠绯荤粺鏃堕棿
+ * @return 鏍煎紡鍖栫殑鏃堕棿瀛楃涓诧紝鏍煎紡涓� "yyyy-MM-dd HH:mm:ss"
+ */
+ public static String getCurrentSystemTime() {
+ LocalDateTime now = LocalDateTime.now();
+ DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
+ return now.format(formatter);
+ }
+
+ /**
+ * 鑾峰彇褰撳墠绯荤粺鏃堕棿锛堣嚜瀹氫箟鏍煎紡锛�
+ * @param pattern 鏃堕棿鏍煎紡妯″紡锛屼緥濡� "yyyy-MM-dd HH:mm:ss"銆�"yyyy/MM/dd HH:mm:ss" 绛�
+ * @return 鏍煎紡鍖栫殑鏃堕棿瀛楃涓�
+ */
+ public static String getCurrentSystemTime(String pattern) {
+ LocalDateTime now = LocalDateTime.now();
+ DateTimeFormatter formatter = DateTimeFormatter.ofPattern(pattern);
+ return now.format(formatter);
+ }
+
+
+
+ private static void testCode() {
+ String mes_id="hxzkcontrol_20151104";//娑堟伅ID
+ String userId=Usrdell.getUserEmail();//鐢ㄦ埛ID
+ String deviceID=Setsys.getMowerIdValue();//璁惧ID
+ String protiesFilePath="./dikuai.properties";//鍦板潡淇℃伅閰嶇疆鏂囦欢
+ String json = PropertiesFileUploader.movePathSend(mes_id,userId, deviceID, protiesFilePath);//鐢熸垚缁欒澶囦笅鍙戠殑JSON
+ sendMQTT(json, host, clientId,deviceID);
+ }
+
+ private static void sendMQTT(String messageJson, String host, String clientId,String deviceID) {
+ try {
+ String topic="app/p/mower/"+deviceID+"/path";
+ MqttConnectOptions options = new MqttConnectOptions();
+ options.setCleanSession(true);
+ MqttClient client = new MqttClient(host, clientId);
+ client.connect(options);
+ // 娣诲姞鍏抽棴閽╁瓙锛岀▼搴忛��鍑烘椂鍏抽棴杩炴帴
+ Runtime.getRuntime().addShutdownHook(new Thread(() -> {
+ try {
+ if (client.isConnected()) {
+ client.disconnect();
+ client.close();
+ }
+ } catch (Exception e) {
+ }
+ }));
+ MqttMessage message = new MqttMessage();
+ message.setPayload(messageJson.getBytes("UTF-8"));
+ client.publish(topic, message);
+ System.out.println("鍙戦�佹暟鎹埌涓婚: " + topic);
+ } catch (MqttException e) {
+ throw new RuntimeException(e);
+ } catch (UnsupportedEncodingException e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+}
diff --git a/src/set/Sets.java b/src/set/Sets.java
index 020f3f4..00d5325 100644
--- a/src/set/Sets.java
+++ b/src/set/Sets.java
@@ -110,6 +110,8 @@
mainPanel.add(scrollPane, BorderLayout.CENTER);
add(mainPanel, BorderLayout.CENTER);
+
+ setupEventHandlers();
}
private JPanel createSettingsPanel() {
@@ -1066,43 +1068,34 @@
return trimmed;
}
+ private void addActionListenerUnique(JButton button, ActionListener listener) {
+ if (button == null) return;
+ for (ActionListener al : button.getActionListeners()) {
+ button.removeActionListener(al);
+ }
+ button.addActionListener(listener);
+ }
+
private void setupEventHandlers() {
// 鍓茶崏鏈虹紪鍙风紪杈戞寜閽簨浠�
- if (mowerIdEditBtn != null) {
- mowerIdEditBtn.addActionListener(e -> editMowerId());
- }
+ addActionListenerUnique(mowerIdEditBtn, e -> editMowerId());
// 鍓茶崏鏈洪暱瀹界紪杈戞寜閽簨浠�
- if (mowerSizeEditBtn != null) {
- mowerSizeEditBtn.addActionListener(e -> editMowerSize());
- }
+ addActionListenerUnique(mowerSizeEditBtn, e -> editMowerSize());
// 鍓茶崏瀹夊叏璺濈缂栬緫鎸夐挳浜嬩欢
- if (mowingSafetyDistanceEditBtn != null) {
- mowingSafetyDistanceEditBtn.addActionListener(e -> editMowingSafetyDistance());
- }
+ addActionListenerUnique(mowingSafetyDistanceEditBtn, e -> editMowingSafetyDistance());
- if (baseStationIdEditBtn != null) {
- baseStationIdEditBtn.addActionListener(e -> editBaseStationId());
- }
+ addActionListenerUnique(baseStationIdEditBtn, e -> editBaseStationId());
// 妫�鏌ユ洿鏂版寜閽簨浠�
- if (checkUpdateBtn != null) {
- checkUpdateBtn.addActionListener(e -> checkForUpdates());
- }
+ addActionListenerUnique(checkUpdateBtn, e -> checkForUpdates());
- if (handheldEditBtn != null) {
- handheldEditBtn.addActionListener(e -> editHandheldMarkerId());
- }
+ addActionListenerUnique(handheldEditBtn, e -> editHandheldMarkerId());
- if (feedbackButton != null) {
- feedbackButton.addActionListener(e -> showFeedbackDialog());
- }
+ addActionListenerUnique(feedbackButton, e -> showFeedbackDialog());
- if (idleTrailEditBtn != null) {
- idleTrailEditBtn.addActionListener(e -> editIdleTrailDuration());
- }
-
+ addActionListenerUnique(idleTrailEditBtn, e -> editIdleTrailDuration());
}
private void editMowerId() {
@@ -1808,7 +1801,6 @@
@Override
public void setVisible(boolean visible) {
if (visible) {
- setupEventHandlers();
loadData(); // 姣忔鏄剧ず鏃堕噸鏂板姞杞芥暟鎹�
}
super.setVisible(visible);
diff --git a/src/user/ZhaohuiMima.java b/src/user/ZhaohuiMima.java
index 421c39e..54ab6de 100644
--- a/src/user/ZhaohuiMima.java
+++ b/src/user/ZhaohuiMima.java
@@ -1,5 +1,7 @@
package user;
+import login.EmailCodeSender;
+import login.PasswordReset;
import javax.swing.*;
import java.awt.*;
import java.awt.event.ActionEvent;
@@ -20,7 +22,6 @@
private JLabel tipLabel;
private Timer timer;
private int countdown = 60;
- private String generatedCode; // 瀛樺偍鐢熸垚鐨勯獙璇佺爜
// 涓婚棰滆壊 (鍙傝�� Denglu.java)
private final Color THEME_COLOR = new Color(46, 139, 87);
@@ -170,6 +171,13 @@
});
}
+ // 閭楠岃瘉鏂规硶
+ private boolean isValidEmail(String email) {
+ // 绠�鍗曠殑閭鏍煎紡楠岃瘉
+ String emailRegex = "^[a-zA-Z0-9_+&*-]+(?:\\.[a-zA-Z0-9_+&*-]+)*@(?:[a-zA-Z0-9-]+\\.)+[a-zA-Z]{2,7}$";
+ return email != null && email.matches(emailRegex);
+ }
+
private void setupEvents() {
getCodeButton.addActionListener(new ActionListener() {
@Override
@@ -177,15 +185,62 @@
String email = emailField.getText().trim();
if (email.isEmpty()) {
JOptionPane.showMessageDialog(ZhaohuiMima.this, "璇疯緭鍏ラ偖绠�", "鎻愮ず", JOptionPane.WARNING_MESSAGE);
+ emailField.requestFocus();
return;
}
- // 杩欓噷搴旇娣诲姞鍙戦�侀獙璇佺爜鐨勯�昏緫
- // 妯℃嫙鐢熸垚楠岃瘉鐮�
- generatedCode = String.valueOf((int)((Math.random() * 9 + 1) * 100000));
+ // 楠岃瘉閭鏍煎紡
+ if (!isValidEmail(email)) {
+ JOptionPane.showMessageDialog(ZhaohuiMima.this,
+ "璇疯緭鍏ユ湁鏁堢殑閭鍦板潃",
+ "杈撳叆閿欒",
+ JOptionPane.WARNING_MESSAGE);
+ emailField.requestFocus();
+ return;
+ }
- startCountdown();
- JOptionPane.showMessageDialog(ZhaohuiMima.this, "楠岃瘉鐮佸凡鍙戦��: " + generatedCode, "鎻愮ず", JOptionPane.INFORMATION_MESSAGE);
+ // 绂佺敤鎸夐挳锛岄槻姝㈤噸澶嶇偣鍑�
+ getCodeButton.setEnabled(false);
+
+ // 鍦ㄦ柊绾跨▼涓皟鐢ˋPI锛岄伩鍏嶉樆濉濽I
+ new Thread(() -> {
+ try {
+ // 璋冪敤閭欢楠岃瘉鐮佸彂閫丄PI
+ EmailCodeSender.EmailCodeResponse response = EmailCodeSender.sendEmailCode(email);
+
+ // 鍦‥DT绾跨▼涓洿鏂癠I
+ SwingUtilities.invokeLater(() -> {
+ if (response.isSuccess()) {
+ // 鍙戦�佹垚鍔燂紝鏄剧ず鎻愮ず骞跺紑濮嬪�掕鏃�
+ JOptionPane.showMessageDialog(ZhaohuiMima.this,
+ "楠岃瘉鐮佸凡鍙戦�佸埌鎮ㄧ殑閭",
+ "鎻愮ず",
+ JOptionPane.INFORMATION_MESSAGE);
+
+ // 寮�濮�60绉掑�掕鏃�
+ startCountdown();
+ } else {
+ // 鍙戦�佸け璐ワ紝鏄剧ず閿欒淇℃伅骞舵仮澶嶆寜閽�
+ getCodeButton.setEnabled(true);
+ String errorMessage = response.getMessage() != null ?
+ response.getMessage() : "楠岃瘉鐮佸彂閫佸け璐�";
+ JOptionPane.showMessageDialog(ZhaohuiMima.this,
+ errorMessage,
+ "閿欒",
+ JOptionPane.ERROR_MESSAGE);
+ }
+ });
+ } catch (Exception ex) {
+ // 寮傚父澶勭悊锛屾仮澶嶆寜閽苟鏄剧ず閿欒
+ SwingUtilities.invokeLater(() -> {
+ getCodeButton.setEnabled(true);
+ JOptionPane.showMessageDialog(ZhaohuiMima.this,
+ "鍙戦�侀獙璇佺爜鏃跺彂鐢熼敊璇�: " + ex.getMessage(),
+ "閿欒",
+ JOptionPane.ERROR_MESSAGE);
+ });
+ }
+ }).start();
}
});
@@ -280,58 +335,97 @@
private void savePassword() {
String email = emailField.getText().trim();
String code = codeField.getText().trim();
- String password = new String(passwordField.getPassword());
- String confirmPassword = new String(confirmPasswordField.getPassword());
+ String newPassword = new String(passwordField.getPassword()).trim();
+ String confirmPassword = new String(confirmPasswordField.getPassword()).trim();
+ // 杈撳叆楠岃瘉
if (email.isEmpty()) {
JOptionPane.showMessageDialog(this, "璇疯緭鍏ラ偖绠�", "閿欒", JOptionPane.ERROR_MESSAGE);
- return;
- }
- if (code.isEmpty()) {
- JOptionPane.showMessageDialog(this, "璇疯緭鍏ラ獙璇佺爜", "閿欒", JOptionPane.ERROR_MESSAGE);
+ emailField.requestFocus();
return;
}
- // 楠岃瘉楠岃瘉鐮�
- if (generatedCode == null || !generatedCode.equals(code)) {
- JOptionPane.showMessageDialog(this, "楠岃瘉鐮侀敊璇�", "閿欒", JOptionPane.ERROR_MESSAGE);
+ // 楠岃瘉閭鏍煎紡
+ if (!isValidEmail(email)) {
+ JOptionPane.showMessageDialog(this, "璇疯緭鍏ユ湁鏁堢殑閭鍦板潃", "閿欒", JOptionPane.ERROR_MESSAGE);
+ emailField.requestFocus();
+ return;
+ }
+
+ if (code.isEmpty()) {
+ JOptionPane.showMessageDialog(this, "璇疯緭鍏ラ獙璇佺爜", "閿欒", JOptionPane.ERROR_MESSAGE);
+ codeField.requestFocus();
return;
}
- if (password.length() < 6) {
+ if (newPassword.isEmpty()) {
+ JOptionPane.showMessageDialog(this, "璇疯緭鍏ユ柊瀵嗙爜", "閿欒", JOptionPane.ERROR_MESSAGE);
+ passwordField.requestFocus();
+ return;
+ }
+
+ if (newPassword.length() < 6) {
JOptionPane.showMessageDialog(this, "瀵嗙爜闀垮害涓嶈兘灏戜簬6涓瓧绗�", "閿欒", JOptionPane.ERROR_MESSAGE);
+ passwordField.requestFocus();
return;
}
- if (password.length() > 25) {
+ if (newPassword.length() > 25) {
JOptionPane.showMessageDialog(this, "瀵嗙爜闀垮害涓嶈兘瓒呰繃25涓瓧绗�", "閿欒", JOptionPane.ERROR_MESSAGE);
+ passwordField.requestFocus();
return;
}
- if (!password.equals(confirmPassword)) {
+
+ if (confirmPassword.isEmpty()) {
+ JOptionPane.showMessageDialog(this, "璇疯緭鍏ョ‘璁ゅ瘑鐮�", "閿欒", JOptionPane.ERROR_MESSAGE);
+ confirmPasswordField.requestFocus();
+ return;
+ }
+
+ if (!newPassword.equals(confirmPassword)) {
JOptionPane.showMessageDialog(this, "涓ゆ杈撳叆鐨勫瘑鐮佷笉涓�鑷�", "閿欒", JOptionPane.ERROR_MESSAGE);
+ confirmPasswordField.requestFocus();
return;
}
- // 楠岃瘉閭鏄惁鍖归厤 (鍙�夛紝鏍规嵁闇�姹�)
- String savedEmail = Usrdell.getProperty("email");
- if (savedEmail != null && !savedEmail.equals(email)) {
- // 杩欓噷鍋囪蹇呴』鍖归厤宸插瓨閭锛屾垨鑰呰繖鏄竴涓柊鍔熻兘鍏佽浠绘剰閭鎵惧洖锛�
- // 閫氬父鎵惧洖瀵嗙爜闇�瑕佸尮閰嶈处鍙风粦瀹氱殑閭
- // 濡傛灉鏈湴娌℃湁瀛橀偖绠憋紝鎴栬�呰緭鍏ョ殑閭涓嶅
- // JOptionPane.showMessageDialog(this, "閭涓嶅尮閰�", "閿欒", JOptionPane.ERROR_MESSAGE);
- // return;
- }
-
- // 杩欓噷搴旇楠岃瘉楠岃瘉鐮佹槸鍚︽纭�
- // ...
-
- // 淇濆瓨瀵嗙爜
- try {
- Usrdell.updateProperty("password", password);
- JOptionPane.showMessageDialog(this, "瀵嗙爜淇敼鎴愬姛", "鎴愬姛", JOptionPane.INFORMATION_MESSAGE);
- dispose();
- } catch (Exception ex) {
- JOptionPane.showMessageDialog(this, "淇濆瓨澶辫触: " + ex.getMessage(), "閿欒", JOptionPane.ERROR_MESSAGE);
- }
+ // 绂佺敤淇濆瓨鎸夐挳锛岄槻姝㈤噸澶嶆彁浜�
+ saveButton.setEnabled(false);
+
+ // 鍦ㄦ柊绾跨▼涓皟鐢ˋPI锛岄伩鍏嶉樆濉濽I
+ new Thread(() -> {
+ try {
+ // 璋冪敤瀵嗙爜閲嶇疆API
+ PasswordReset.ResetPasswordResponse response = PasswordReset.resetPassword(
+ email, code, newPassword, confirmPassword);
+
+ // 鍦‥DT绾跨▼涓洿鏂癠I
+ SwingUtilities.invokeLater(() -> {
+ saveButton.setEnabled(true);
+
+ // 鏄剧ず杩斿洖娑堟伅
+ String message = response.getMessage() != null ?
+ response.getMessage() : (response.isSuccess() ? "瀵嗙爜閲嶇疆鎴愬姛" : "瀵嗙爜閲嶇疆澶辫触");
+ int messageType = response.isSuccess() ?
+ JOptionPane.INFORMATION_MESSAGE : JOptionPane.ERROR_MESSAGE;
+ String title = response.isSuccess() ? "鎴愬姛" : "澶辫触";
+
+ JOptionPane.showMessageDialog(this, message, title, messageType);
+
+ // 濡傛灉鎴愬姛锛屽叧闂獥鍙�
+ if (response.isSuccess()) {
+ dispose();
+ }
+ });
+ } catch (Exception e) {
+ // 寮傚父澶勭悊锛屾仮澶嶆寜閽苟鏄剧ず閿欒
+ SwingUtilities.invokeLater(() -> {
+ saveButton.setEnabled(true);
+ JOptionPane.showMessageDialog(this,
+ "閲嶇疆瀵嗙爜鏃跺彂鐢熼敊璇�: " + e.getMessage(),
+ "閿欒",
+ JOptionPane.ERROR_MESSAGE);
+ });
+ }
+ }).start();
}
private JPanel createPasswordPanel() {
diff --git a/user.properties b/user.properties
index ed311c0..7166250 100644
--- a/user.properties
+++ b/user.properties
@@ -1,11 +1,11 @@
#Updated User Properties
-#Wed Dec 24 17:05:38 CST 2025
-email=7892584@qq.com
+#Fri Dec 26 17:15:14 CST 2025
+email=981894274@qq.com
language=zh
-lastLoginTime=1766567138180
-password=123
+lastLoginTime=1766740514340
+password=123456
registrationTime=-1
rememberPassword=1
status=-1
userId=-1
-userName=233
+userName=981894274@qq.com
--
Gitblit v1.10.0