Compare commits
2263 Commits
release/ma
...
01d3806d5f
| Author | SHA1 | Date | |
|---|---|---|---|
| 01d3806d5f | |||
| 107e4e9771 | |||
|
|
716d720782 | ||
|
|
6b5bacc49b | ||
|
|
409bc7b1fd | ||
|
|
ec6a5df8af | ||
|
|
029b96ae99 | ||
|
|
14002e7331 | ||
| 14dfe2806c | |||
| 798c7b0592 | |||
| 9bd10581f4 | |||
| 1f288fe5e3 | |||
| 72602eb245 | |||
| 983d53268d | |||
| f3aeeb3584 | |||
| 5d3692a204 | |||
| f2a074b2f6 | |||
| 6a7a37dcec | |||
|
|
c4d2780f0e | ||
|
|
1da6b7728c | ||
|
|
0faf77899b | ||
|
|
e4940019bf | ||
|
|
0da66ff210 | ||
|
|
5dd862ff79 | ||
|
|
edaec9884d | ||
|
|
76eeb2be53 | ||
|
|
cb6f94d2d4 | ||
|
|
28656c44c8 | ||
|
|
6757a89d04 | ||
|
|
9be1a1e307 | ||
|
|
2168978f61 | ||
|
|
54466b935d | ||
|
|
c970ebe691 | ||
|
|
1c5a3a12b9 | ||
|
|
6e06000083 | ||
|
|
dea2b3be42 | ||
|
|
bcf51aea23 | ||
|
|
0c9d5404c6 | ||
|
|
93429839c0 | ||
|
|
27859c3e28 | ||
|
|
f02c0930a6 | ||
|
|
d57bb83b25 | ||
| 731e34f133 | |||
| 75eca8d6ba | |||
| 3e53401f76 | |||
|
|
b6a068ebcd | ||
|
|
dc291ea086 | ||
|
|
2e846e671a | ||
|
|
a5093311f9 | ||
|
|
aed338a6d7 | ||
|
|
8bdb49d25c | ||
|
|
5d53a8cd42 | ||
|
|
61b7f3072f | ||
|
|
a1f489f3a1 | ||
|
|
fc3fd877a8 | ||
|
|
fc72d2c430 | ||
|
|
1ac01dd090 | ||
|
|
3bbdf7c672 | ||
|
|
0646484fba | ||
|
|
96b8613741 | ||
|
|
cf30226a51 | ||
|
|
3c15a3ff68 | ||
|
|
0c904be227 | ||
|
|
7759b56123 | ||
|
|
d5bfaa8822 | ||
| 967c0cbc01 | |||
| 417e34b41a | |||
|
|
d51aa84647 | ||
|
|
5895bc6ab6 | ||
|
|
3301869f20 | ||
|
|
1ec42f4ad5 | ||
| cc506ff7e9 | |||
|
|
f2d43f06f4 | ||
|
|
9251df49f8 | ||
| 430156f4e8 | |||
|
|
d1123aedcc | ||
| 8c007077a3 | |||
|
|
d63b4b4e63 | ||
|
|
b826f0bf39 | ||
|
|
1decd8e258 | ||
|
|
1286e84488 | ||
| a252fdf7f9 | |||
| 807d802178 | |||
| 53f1b548be | |||
| 45dd78032a | |||
| c160da5132 | |||
| b23faeeee2 | |||
| 67789abca4 | |||
| 1c78d66aab | |||
| 528bc69923 | |||
|
|
22880d128d | ||
| 9c56a102cc | |||
| 2f59fe074f | |||
| 9c61b1c8fe | |||
| e30fdf7401 | |||
| ba2d10afbc | |||
| 6146112d04 | |||
| 412550df27 | |||
| 497421e7fe | |||
| 891527426c | |||
|
|
3e334d7956 | ||
|
|
8f0d0953b2 | ||
| f5c3621a5d | |||
|
|
9a1a0045e0 | ||
| 6223c8e994 | |||
| 67bbee49fd | |||
| ad62ceb32a | |||
| 082afe9e94 | |||
| 49288c3a31 | |||
| 81624e36db | |||
| a526b122d1 | |||
|
|
d882b2e817 | ||
|
|
ebf6427d42 | ||
| 77fe03d361 | |||
| 7a44d67dbf | |||
| 55ce2c6c7e | |||
| a426caaca3 | |||
| 7cb7ce2836 | |||
| 8e075f1da4 | |||
|
|
0f0fde2a3e | ||
|
|
8c6389a1f6 | ||
| 652f82b6a4 | |||
| 7ca2528dcf | |||
|
|
a7800913d2 | ||
|
|
1eaec64ff4 | ||
| e603952332 | |||
| 2bc8b8ef96 | |||
| 0ce968b919 | |||
|
|
dfc9ae4db2 | ||
|
|
a3505c6d95 | ||
|
|
6db0afd515 | ||
|
|
b1e6183dd1 | ||
| 30d08356c0 | |||
| 64cc29f456 | |||
|
|
2b3e12a11c | ||
|
|
d4a4724f61 | ||
|
|
ba6e2bd24c | ||
|
|
a38895b028 | ||
|
|
69a95e66ca | ||
|
|
40518cab37 | ||
|
|
46d61cb73f | ||
| 08f20fd1fe | |||
| d7edc166b3 | |||
|
|
79ad02f66b | ||
|
|
5e261b55c7 | ||
|
|
bc92fcbaf4 | ||
|
|
c6aec917c2 | ||
| 6bc500e78f | |||
| 4c43b98c02 | |||
|
|
5bae785a9f | ||
|
|
7b619aa4cb | ||
| c93ad6daa9 | |||
| 0047be7a03 | |||
| 4ef209cfd4 | |||
| a19751b4b7 | |||
|
|
bb0e5a4263 | ||
|
|
9e9df5367d | ||
| ba8a2c52de | |||
| 39d8c7efcf | |||
|
|
401910901a | ||
|
|
3f5ce6e0e7 | ||
| 0787025151 | |||
| 08b26872ff | |||
| 5bbf1326bb | |||
|
|
c5e27cd220 | ||
|
|
112e9c3bc9 | ||
|
|
ce95cb5080 | ||
|
|
71211bfbc3 | ||
| 72ad977dcb | |||
|
|
6400e79929 | ||
|
|
dd8c72f7d7 | ||
| 13151b65f5 | |||
| 9f523d5953 | |||
| 4879cfeb60 | |||
| 9e252b16ef | |||
| e64add14af | |||
| 3beb27e491 | |||
| 501032ef17 | |||
|
|
cb25bdd2e0 | ||
|
|
7a9fb0213b | ||
| cd767dce6f | |||
| bf95b85841 | |||
| 9e58bd9e7d | |||
| d0ec5c5c26 | |||
| ab8aa5ea5c | |||
| aefcd2fdb0 | |||
| e74eab1070 | |||
|
|
34da437a26 | ||
|
|
f84935d0bd | ||
| 35edaa0f27 | |||
| f43099e19e | |||
| 8079877734 | |||
| ef686e38ac | |||
| 100019d2a4 | |||
|
|
12af237d76 | ||
|
|
44dbbb2a4b | ||
| 9f42e153a4 | |||
| 4fa70a1c90 | |||
| dfb34916e7 | |||
| 9f7987306c | |||
|
|
d3fc70fbf2 | ||
|
|
17645d17e5 | ||
|
|
258eea5277 | ||
|
|
bb1d3bd359 | ||
|
|
6a8c87ed95 | ||
|
|
eb3826927d | ||
|
|
7720c8c771 | ||
|
|
b459148d58 | ||
|
|
eadda18d1e | ||
|
|
d403df51ec | ||
| 6903b98b60 | |||
| 81bf65515c | |||
| 8e984eb283 | |||
|
|
afc6041570 | ||
| bce368248c | |||
| ca7121dcda | |||
|
|
9a206f9979 | ||
|
|
eb7a46c7e8 | ||
|
|
95ef68a784 | ||
|
|
6429288fd9 | ||
| c5af194876 | |||
| da84e1e4b4 | |||
| 95a9c81a1b | |||
| 81c0d7eeac | |||
|
|
fbc473735c | ||
|
|
9f48a2ce09 | ||
| 459c743ce4 | |||
| ce3516916d | |||
| 0692b29065 | |||
| 94cafbd10c | |||
| 5c2008ec4a | |||
|
|
4e4b8bd4d2 | ||
|
|
9c19d061be | ||
| 7f094265da | |||
| 22bc8750c8 | |||
| a940105fa4 | |||
| 4c0edf09bd | |||
| bd69793a72 | |||
|
|
a643338916 | ||
|
|
9344a946ad | ||
| fab0c7b372 | |||
| fc0867d9b1 | |||
| c36ba6211a | |||
|
|
aa0a787e3f | ||
|
|
964ee1c5cc | ||
| ac98cd01db | |||
| 70d498b90d | |||
| ae1a2eff2a | |||
| b54eaea7e3 | |||
| aa2363b9a5 | |||
| 41ef9132e9 | |||
| 3b5b57ab08 | |||
| 2ec9ef3290 | |||
| fe3fbbe135 | |||
| 01e82b4c23 | |||
|
|
e085275aee | ||
|
|
fa7271567e | ||
| 05049ae7a2 | |||
| b023a68f83 | |||
| 6cd42b799a | |||
| 6e1ed7f9b8 | |||
| b7be16738b | |||
| 6da5e91ec1 | |||
| 00c0a65547 | |||
| 77aab576de | |||
| 5b2c77f81b | |||
| 96040f2349 | |||
| a710fdd432 | |||
| d598f53d3c | |||
| 62bf538d96 | |||
| 456cb1ff19 | |||
| cbca666e7b | |||
| d622195f9d | |||
| 1917fd518d | |||
| 96170a9956 | |||
| 8205fb5290 | |||
| 8f72686809 | |||
| 37ddf6f441 | |||
| dbf9b2d722 | |||
| a91f9ccdd4 | |||
| dac51afe73 | |||
| 3aa744895f | |||
| 9535d8ce59 | |||
| 6c8b316dfd | |||
| e366d5a2c5 | |||
| b6add404b3 | |||
| fcbe4762b3 | |||
| e750adcc94 | |||
|
|
1c782f8fd7 | ||
|
|
b58b8df88f | ||
|
|
c09f734a30 | ||
| 1464689657 | |||
|
|
a2ff345da5 | ||
| 9ae1626309 | |||
| 70a41bdfbc | |||
|
|
8757db4f3d | ||
|
|
a8e3304db2 | ||
|
|
26f2299381 | ||
| c1a5799da7 | |||
| 94c0e81335 | |||
| b9641474ba | |||
| 059d6edc12 | |||
| 97c5be7b22 | |||
| c4da4ea111 | |||
|
|
db1048d875 | ||
| bbc8b025a9 | |||
| 630f6b2737 | |||
| d14fdfee79 | |||
| c14db62c0a | |||
|
|
9166bf1a1a | ||
|
|
84c024eab8 | ||
|
|
b86f3c9f7e | ||
| e2009617db | |||
| 65b17fe109 | |||
| 0917154283 | |||
| 0f525c6c00 | |||
| 4beae1094b | |||
| cefdac133e | |||
| a466f269c2 | |||
| 97f0c8f65f | |||
| ad00ac08ca | |||
| d236057f2a | |||
| 62e3e9c16f | |||
| 604c529b42 | |||
| bc612481dc | |||
| 2f3fa695b2 | |||
| 313fc19dac | |||
| f36e0488ea | |||
| f239c8c02b | |||
|
|
1d4017bafd | ||
|
|
8c98f91445 | ||
| 18f5528d59 | |||
| 88ce191950 | |||
|
|
f3d6d7b000 | ||
| ef84f32ca0 | |||
| 3886aeaa46 | |||
| 8750ea355a | |||
|
|
b107fa82df | ||
|
|
e56a6176a9 | ||
|
|
e35ed2c768 | ||
|
|
52094d58e7 | ||
|
|
e4e6cfbff7 | ||
|
|
15f2b78c94 | ||
|
|
1fd1f7dd47 | ||
|
|
2a6d3c1b58 | ||
| 59e33c22b7 | |||
| e5eecbfe8d | |||
| 9759cf4740 | |||
| e8766b9af3 | |||
| 4fed5f7439 | |||
|
|
c3e0a61ff7 | ||
|
|
58212e92ec | ||
| 5efaaf01b2 | |||
| 18c94ad1e0 | |||
| e825c9bd75 | |||
| 1af705592a | |||
|
|
d426fb34a2 | ||
|
|
8c3e1fdda5 | ||
|
|
a76b9ba365 | ||
| cd74022d04 | |||
|
|
d5b972ab16 | ||
| a3e63c9877 | |||
| 0c227a1efa | |||
|
|
59602540a3 | ||
| 4578cb5778 | |||
|
|
9959a03ccc | ||
|
|
ff43ffaba6 | ||
|
|
1c32aaa46c | ||
| db5f435a4d | |||
|
|
c9f9ef0ce2 | ||
|
|
3b6a9882d2 | ||
|
|
854847a6f4 | ||
|
|
309d95ab3c | ||
|
|
422d547cfd | ||
|
|
e6a0706d61 | ||
| 19c08f4237 | |||
| 6ac9680c64 | |||
| 4ce6fb4190 | |||
|
|
6b7abafb68 | ||
|
|
02f7031a67 | ||
| 3d67ac71f3 | |||
|
|
67f0ce7c6c | ||
|
|
5fbcaf9077 | ||
| ebb19ea15e | |||
|
|
5efa5cad33 | ||
|
|
f9dfd61b89 | ||
| 42aed5804b | |||
|
|
df5ee235f2 | ||
|
|
ad2bb7062e | ||
|
|
4fbacb37c1 | ||
|
|
3150f5ae57 | ||
|
|
20cf415635 | ||
|
|
7bd32914a1 | ||
|
|
24d54ea9ea | ||
| c00c2e738b | |||
|
|
6772610129 | ||
|
|
a681a298f4 | ||
|
|
e6d5d4f614 | ||
|
|
187c38ad61 | ||
|
|
95f6f02290 | ||
| ab7ef19657 | |||
|
|
d837f0dc78 | ||
|
|
ab6cc04483 | ||
| 9110e0dd34 | |||
| 0f084c27ea | |||
| b1b465a05a | |||
| 2e4b1516cc | |||
| 1e389bec86 | |||
| 2d0936f0f3 | |||
| dab253c313 | |||
| ed86cd45ad | |||
| 814324430c | |||
| 1d006342fb | |||
| 24fe265172 | |||
| 79e19a029b | |||
| 227a20f6f2 | |||
| efa26d912d | |||
|
|
ea19e915db | ||
| 41759ca44b | |||
| 29e1d864ae | |||
| 6cfd420e46 | |||
| 51024508b9 | |||
| b7b07b8843 | |||
| c1d26a87ce | |||
| d59a69e6f4 | |||
|
|
042501f9b1 | ||
|
|
9e6fcb4f73 | ||
| 9386a2c6c4 | |||
| c43a716104 | |||
|
|
950707ab44 | ||
|
|
b0e5f39765 | ||
| 5eebb878ca | |||
|
|
d568129843 | ||
| d093aa9d1a | |||
| 3c1d180ed6 | |||
| b9c24386b9 | |||
|
|
8f53902d18 | ||
| c79535ac3f | |||
| 106528ce08 | |||
|
|
23eda80389 | ||
|
|
eccd2a35e9 | ||
| 9c69aeae53 | |||
| 5bac740efd | |||
|
|
fa74236035 | ||
|
|
630dfe98a4 | ||
| c922563919 | |||
| ce68696934 | |||
| 5d8bdf9ecc | |||
| e3b0d3bc0a | |||
| 5f5f2c83d7 | |||
| aff51a2793 | |||
| 4c5d8d3c61 | |||
| f667099f4f | |||
| d5a74c1ff3 | |||
| c187d25d74 | |||
| f20a85a0e2 | |||
| 4f93ec144b | |||
| de16437d08 | |||
| c67d197da0 | |||
| d8f0188596 | |||
| ddc089faa4 | |||
| f5ecd34a9c | |||
| 3c071378ad | |||
| 8b2aab2e5e | |||
| c4a42b03f6 | |||
| 0dad9ff618 | |||
| 136bcdf82b | |||
| a59acb0903 | |||
| feca192f53 | |||
| 179b79812a | |||
| 94cf82340a | |||
| c649907222 | |||
| c93ae85b65 | |||
| 6441bfbbba | |||
| 933522482b | |||
| 56b56981b1 | |||
| 9e2ea2de62 | |||
| 7005b75e11 | |||
| 5b09d2cbf5 | |||
| 126ac209c6 | |||
| 98eb29eeb5 | |||
| ee551a0be2 | |||
| c3cbb61c16 | |||
| 71f0293cd9 | |||
| 35604e5130 | |||
| 18c38b020e | |||
| 6e9213ec5a | |||
| 83ba69c950 | |||
| 3cc329f983 | |||
| c42ee8a1bf | |||
| 9a650afc7d | |||
| 45a336ced3 | |||
| e258166a16 | |||
| f9ec733f07 | |||
| 54b09b4940 | |||
| 6d0c29f5c3 | |||
| 23523f73da | |||
| e45d572078 | |||
| eebb790aeb | |||
| 9c6573f1a6 | |||
| 6a5282e4d5 | |||
| 3c5a5ff225 | |||
| e4ce7e9e63 | |||
| 1089a5a2a5 | |||
| 156fcfae6b | |||
| 7436fa17c0 | |||
| d9f19f1728 | |||
| 81c417ed76 | |||
| 59a3015170 | |||
| b02009bf14 | |||
| caa9985d11 | |||
| 80957bfc00 | |||
| 552ec828ab | |||
| 42273750f4 | |||
| 45d6af92e8 | |||
| c28db81893 | |||
| 1e25ae36f1 | |||
| 9bf40d879f | |||
| 878f556a0b | |||
| 4ad2cd027c | |||
| 132f48eb60 | |||
| 5b33e31504 | |||
| e16268a013 | |||
| 739e637267 | |||
| 7edc959432 | |||
| c444d5a69f | |||
| 830d06a900 | |||
| 0fcd8e5444 | |||
| 020cfe9016 | |||
| 39903f3da6 | |||
| b1d682a909 | |||
| 07d60303db | |||
| 5287d83b82 | |||
| e2085190d1 | |||
| 565b5c3de1 | |||
| fd29452e0c | |||
| 0f93099d04 | |||
| e2d50a6dfa | |||
| c4d20cd522 | |||
| 229e1353f4 | |||
| 07571aaad1 | |||
| 3c2b4ffc48 | |||
| bb0a3bd1cd | |||
| 3bd9ff82d7 | |||
| f0fccaaf51 | |||
| 2041809ea6 | |||
| b90df7468e | |||
| e2e0bd6b47 | |||
| 785ae33e86 | |||
| 20f7dc0ef9 | |||
| 0155154664 | |||
| d264c29557 | |||
| 432149dce2 | |||
| 5b3a52152a | |||
| 301f58bc62 | |||
| 64318de24a | |||
| fb01250142 | |||
| 0beec5392e | |||
| f551ba452f | |||
| f4b22fe874 | |||
| e95444266b | |||
| e361960e51 | |||
| d0a9c05d4b | |||
| f852927116 | |||
| daa88889d0 | |||
| 766e75f2ed | |||
| eb7f2a1419 | |||
| c7c69417ef | |||
| 9f548d299b | |||
| 1dc6c6f8c4 | |||
| 5472e59a84 | |||
| d379f778dc | |||
| ec44c2a6b5 | |||
| 1f77500d61 | |||
| 060db899cf | |||
| 9fc8f52aca | |||
| 9af1bc867a | |||
| e92bb0c7cd | |||
| 1d07d7d88a | |||
| ec7d84b354 | |||
| 0a2c5e028f | |||
| 4379b9cff1 | |||
| 1b7c2041be | |||
| f3632f53e3 | |||
| d76a9e6afd | |||
| e67acc4319 | |||
| 373a360e76 | |||
| f541bee0e7 | |||
| 75d086f680 | |||
| 81ca723486 | |||
| d51bbffb3e | |||
| 07aad4afa0 | |||
| 6495bb2be3 | |||
| 3d8363c99b | |||
| 333c11f81e | |||
| 77fc3e967a | |||
| a447cde05b | |||
| e8ad241653 | |||
| 1f824f3ae6 | |||
| 370d9402f2 | |||
| 4d518d05b9 | |||
| 8c87333fa2 | |||
| 4273d0efc0 | |||
| a37b64be91 | |||
| 905d296bdf | |||
| 9a25e8ce4a | |||
| 68311e1d8b | |||
| de5da5b299 | |||
| dcd63668bd | |||
|
|
1a52399ec9 | ||
|
|
b01f5f59d1 | ||
| c70231d5de | |||
| d3deec72eb | |||
|
|
a7347c9dc0 | ||
|
|
6ad5d373d5 | ||
| e048b75ed7 | |||
| 469681b96c | |||
| 89457b0593 | |||
| 7a6b257714 | |||
| 443b557623 | |||
|
|
84691f45b5 | ||
| de65f78e89 | |||
| 252cd0a69c | |||
| d77aabca92 | |||
| 13514b277b | |||
| eaf90ab9e8 | |||
| f828983969 | |||
| be6eb64b35 | |||
| abc6c088fe | |||
| 6f44489c6e | |||
| a809905c52 | |||
| 7abab7121a | |||
| 8e31968fd3 | |||
| 3d08e86049 | |||
| e0fdf1cc88 | |||
| 4acdd8adb9 | |||
| d6c5d0e95d | |||
|
|
e8e6f8bc17 | ||
|
|
27983fe8ee | ||
|
|
c3d92aacd5 | ||
|
|
b287ec8529 | ||
| 07d3f6e224 | |||
| fc42f361fa | |||
|
|
424f9a126d | ||
| a042f05401 | |||
| f59adbe9bd | |||
| a0ece486d8 | |||
|
|
4caa0a9b0d | ||
|
|
df5bbc3675 | ||
| 92278cf91b | |||
| 6b165fe5bc | |||
| 64b32dc3a3 | |||
| 301a62a563 | |||
| 1f84b4b3e6 | |||
| a0979caba6 | |||
| 18be52e806 | |||
|
|
627dad7aac | ||
|
|
7166db59bd | ||
| 13759d806b | |||
| 0fd1ddcde1 | |||
|
|
a5e743ce84 | ||
| 161bba896c | |||
|
|
da8338be3f | ||
|
|
ea235b0d5c | ||
| 98ea6004b4 | |||
| 62cbc612a7 | |||
| 589fa8501e | |||
|
|
d6285781f2 | ||
|
|
137ef7045b | ||
|
|
5e066995e8 | ||
|
|
c1c50cb28b | ||
| 3f13f64ab9 | |||
| 5abe45ff34 | |||
|
|
0970127f68 | ||
|
|
93bb8d2f31 | ||
|
|
88d8b75298 | ||
| ea395e87ba | |||
| 8d7b4adf48 | |||
| e3ee724e6f | |||
|
|
9d022ae13e | ||
|
|
8b0f9cfd11 | ||
| f36b3818c5 | |||
| 2ccbbf8893 | |||
| 76219aa4fe | |||
| 5ed3d8dfab | |||
| 4dd3ddb1d0 | |||
| fb16840a98 | |||
| 9ad6acf28c | |||
|
|
774a20257d | ||
|
|
3db0a94981 | ||
| 891b26d493 | |||
| 86a991db81 | |||
|
|
fd8e6fd2e8 | ||
| 78239d3ead | |||
| 174d1bf0d0 | |||
| da9f54982c | |||
| b6993b04c2 | |||
|
|
4cca30ec75 | ||
|
|
b6c43e534b | ||
|
|
942b5eb19b | ||
| 22e5a97143 | |||
|
|
31b2bd97b4 | ||
|
|
3eaa0d017c | ||
| be42550d0a | |||
| 6e32289b98 | |||
|
|
a750a91f7b | ||
|
|
2cf3b75e46 | ||
|
|
9586be40ce | ||
|
|
4494ec7dbc | ||
|
|
33af9d0b9d | ||
|
|
7f30b2d05b | ||
|
|
3cd86042ff | ||
| af1fab644a | |||
| ace53e81f2 | |||
|
|
f179368668 | ||
| 765d404845 | |||
|
|
9134933a07 | ||
|
|
290f6a9a35 | ||
| ac2d1e611b | |||
| 1b75e2ab55 | |||
| de9750b24a | |||
| 595effa04c | |||
|
|
09e24ab062 | ||
|
|
391208f8bd | ||
|
|
3cf47eb723 | ||
|
|
c3ce25315c | ||
|
|
ae71564b94 | ||
|
|
d6bd24865e | ||
|
|
c420300c11 | ||
|
|
4c67fce8d1 | ||
| d5cf4e9d3f | |||
| 4b7fd649a3 | |||
|
|
b8d3b0192d | ||
|
|
1afd86d3ce | ||
|
|
daa133b993 | ||
|
|
bf258ee4f9 | ||
| 2bc17ec4d0 | |||
| 090b9ab6ab | |||
|
|
fb5b52bec2 | ||
|
|
df678a12b9 | ||
| 21f85a7322 | |||
| 4e2590fd0f | |||
| 31c5fef5c0 | |||
|
|
94e26ac912 | ||
|
|
711859ce89 | ||
| 8502fffb68 | |||
| 6f0cc3aaf8 | |||
|
|
ce13874431 | ||
|
|
054c9fd604 | ||
| f5501db19e | |||
| 4609af875e | |||
| 1dad0a008a | |||
|
|
b757cdc5dd | ||
|
|
249351bf52 | ||
|
|
38ca810068 | ||
|
|
bab5c9a8e6 | ||
|
|
4e80493a26 | ||
|
|
12dbe90150 | ||
| 6249d53b7b | |||
| b445f1f11e | |||
|
|
f2c268683c | ||
|
|
f69eaa4fe3 | ||
|
|
a9172dcd36 | ||
|
|
442e87267a | ||
|
|
32c8aaec9b | ||
|
|
112294bd7b | ||
|
|
3bfbd8abc1 | ||
|
|
78341850e1 | ||
|
|
becdbf1891 | ||
|
|
f0b1d3f9ce | ||
|
|
73bab2338e | ||
|
|
448e6d2c40 | ||
|
|
131d782b54 | ||
|
|
d6cc8ab9a2 | ||
|
|
d9e25fd0e4 | ||
|
|
276994759e | ||
| a569ee7736 | |||
| d7762cbfed | |||
| 8356326c7d | |||
|
|
8003a799c2 | ||
|
|
6de1ad150c | ||
|
|
b6a7354322 | ||
|
|
6e96f38c90 | ||
|
|
fc24e1fab8 | ||
|
|
718e1c93f6 | ||
|
|
74540610c6 | ||
|
|
1be4701f6d | ||
| 5c66ece467 | |||
|
|
d3b4d15df8 | ||
|
|
8fc79f6699 | ||
| 3b6b0c7e2c | |||
|
|
91ee58db1b | ||
|
|
af1c839495 | ||
|
|
083416951a | ||
|
|
cd20bdd88f | ||
|
|
5a0fb6fd3f | ||
|
|
93fe0781b2 | ||
|
|
94e00459b6 | ||
|
|
9614985690 | ||
|
|
8c597db8a9 | ||
| 9a81fb7ee4 | |||
|
|
a0bd4cfa38 | ||
|
|
82388b0c19 | ||
|
|
588202311c | ||
|
|
46820505ae | ||
|
|
b030e9c09b | ||
|
|
f1adbb4da7 | ||
|
|
4dfee09abb | ||
|
|
16e4f7c5b5 | ||
|
|
e9e40e53bc | ||
| 31bb29f2fd | |||
|
|
a2625fa73f | ||
|
|
ab804d57c1 | ||
|
|
cef2fca099 | ||
|
|
3d783974fc | ||
|
|
7f5a1615b3 | ||
| c7b46229b5 | |||
| 1482bb6ab2 | |||
| eae4087b3e | |||
| faf98607c4 | |||
| 6c625de936 | |||
| aeb372bc17 | |||
|
|
738144ad22 | ||
|
|
a67b487dc0 | ||
|
|
8613d4fc7a | ||
|
|
6aa1a3d167 | ||
|
|
59ffa38ff7 | ||
| c19e9094d1 | |||
| bf92edb267 | |||
| db55c5597f | |||
| 0c79739867 | |||
| e484f22788 | |||
| c72f382804 | |||
| 6a694cee18 | |||
| 1a077edf0c | |||
|
|
68926757dc | ||
|
|
eea57435e5 | ||
| 1f0e8f9cf2 | |||
|
|
6d6768e6cb | ||
|
|
a84fe12a28 | ||
|
|
be019dcdd0 | ||
|
|
82d65c3015 | ||
|
|
815392fffa | ||
|
|
35e95c835e | ||
|
|
1263409d7c | ||
| e5b184ea6d | |||
| aa0778958e | |||
| 50b78e9898 | |||
| 58af5c5570 | |||
| 63cde1f6a0 | |||
| 89e6ee9eff | |||
| 200c0adfba | |||
|
|
306f4f3987 | ||
|
|
1240a57405 | ||
|
|
a9acc83bdf | ||
| a2d259aea1 | |||
|
|
7ff8a9db22 | ||
|
|
7b6904059f | ||
|
|
eec9c6ebf2 | ||
|
|
1e8884a7c3 | ||
| 9d591bb070 | |||
| db4bad22f4 | |||
| 58bd986090 | |||
|
|
9e5bafc75e | ||
|
|
938ad7366f | ||
|
|
56ec903807 | ||
|
|
5913445257 | ||
|
|
2d1d458929 | ||
|
|
5a0c461961 | ||
|
|
74ad20646d | ||
|
|
604c57c208 | ||
|
|
aca21b9d98 | ||
|
|
b83a416dda | ||
|
|
d1858ddf83 | ||
|
|
aa1c48fcfe | ||
|
|
b19bbf91f2 | ||
|
|
d9e4fb3022 | ||
|
|
cc8f2e0778 | ||
|
|
9b1881349f | ||
|
|
eacceb4b76 | ||
|
|
c50c193a46 | ||
|
|
dfe99ef080 | ||
|
|
98e1f37c1d | ||
|
|
05295b1a0d | ||
|
|
6fb04a66df | ||
|
|
ba14b67c24 | ||
|
|
0a4d6ff13b | ||
|
|
fc2795b83e | ||
|
|
4c726ff747 | ||
|
|
4ed93c7e48 | ||
|
|
acb37bc255 | ||
|
|
9b5040d449 | ||
|
|
fe0d1f39b0 | ||
| 79d2720733 | |||
| 218d828e0d | |||
| 2269662290 | |||
| eaec1e4177 | |||
| eaff87882e | |||
| 0ba28588da | |||
| 25f64831f3 | |||
| d6c869727a | |||
| 77a06e0edd | |||
| 21efcf3ea6 | |||
| d77e1d74b0 | |||
| 1ce6c74f2c | |||
| 3c4b645772 | |||
| 909978467c | |||
| 912c449161 | |||
| 7f05bb2f7d | |||
| cbc760ebaf | |||
|
|
48bb0cbff5 | ||
|
|
1403b7851a | ||
|
|
c36081996d | ||
|
|
14dbc35eda | ||
|
|
64c03768ff | ||
|
|
b806bef0bf | ||
|
|
811d22e229 | ||
|
|
1ee612674e | ||
|
|
cf9b621159 | ||
|
|
03ae184541 | ||
|
|
6b62d26544 | ||
|
|
3883864558 | ||
|
|
1089f37022 | ||
| c661767de3 | |||
| 7b75e6ac69 | |||
| bd1f1deb53 | |||
| e142d50d18 | |||
| 6250e763c3 | |||
|
|
4cda43f3b5 | ||
|
|
fd8d71e2a2 | ||
|
|
87b702c24b | ||
|
|
27cd98f0db | ||
|
|
d1603fbc16 | ||
|
|
96ba29a9a2 | ||
|
|
5d9ca09272 | ||
|
|
64676736b5 | ||
|
|
7106482831 | ||
|
|
b1c8606432 | ||
|
|
0eb02c598e | ||
|
|
b6367d72ba | ||
| 2e76bded8c | |||
| 0e7c07b3b5 | |||
|
|
3e3b1eb868 | ||
|
|
ec0309d6f2 | ||
|
|
8ee7a030bd | ||
|
|
ca9778a416 | ||
| 07504d8412 | |||
| 88796f7f28 | |||
|
|
8764e750ff | ||
|
|
9d2cb29255 | ||
| a1b8f9e000 | |||
| 6f2c670fce | |||
| d21cb4adfc | |||
|
|
97b922c1be | ||
|
|
0af5b2121c | ||
| 36be8b5420 | |||
| a34d775f63 | |||
| 1bee672592 | |||
|
|
cf08f9126e | ||
| 8e938e9f06 | |||
|
|
a08744f71a | ||
|
|
913c4c1ece | ||
|
|
63ee41e3b8 | ||
|
|
08072001a7 | ||
| 6b4d82a67d | |||
|
|
03f3162dc1 | ||
|
|
0eb839e7c7 | ||
|
|
807d3e1c46 | ||
|
|
e6f990b766 | ||
|
|
6dcc492127 | ||
|
|
a2bd2fa6c6 | ||
| 5612b5b1d4 | |||
|
|
2edf7d211b | ||
|
|
890265611a | ||
|
|
48c7182f98 | ||
|
|
2cfd342ef8 | ||
|
|
63513df053 | ||
|
|
bb00d9a714 | ||
|
|
3398992bcd | ||
| 2912463562 | |||
| 3df4433381 | |||
| 1d46a3b6d4 | |||
|
|
a8f868e215 | ||
|
|
78a5bebb4f | ||
|
|
33582922be | ||
|
|
e6234213f0 | ||
|
|
1d9a89d7c7 | ||
|
|
b0560b840f | ||
| 20b15c0b78 | |||
| a4365abd4d | |||
| 1cb02a62e8 | |||
| 67225c1a96 | |||
| 50ecc3a177 | |||
| 63c9ff36a1 | |||
|
|
dc62ca956c | ||
|
|
d45c555415 | ||
| a657464d22 | |||
| b5b67e0c75 | |||
| 619d0e817f | |||
|
|
5d7beca57d | ||
|
|
9a933e74ff | ||
| 0b60dd799f | |||
| a38c15005e | |||
| b5a8c635d6 | |||
| 6b288a3b3c | |||
| 9a5718cc35 | |||
| cc804bac7d | |||
| b18a5a0050 | |||
| 078a0c0dfb | |||
|
|
d080fc04bb | ||
|
|
ae484c9e6c | ||
|
|
39cb20618b | ||
|
|
5b95401204 | ||
| 6b62cf7299 | |||
|
|
af352bbfe8 | ||
|
|
4d7673e8df | ||
|
|
55ec6da74b | ||
|
|
83d9a5befb | ||
|
|
ec836a6470 | ||
|
|
d6f9aa155e | ||
|
|
d3b507ed45 | ||
|
|
b027396567 | ||
|
|
7d0a6ae2bf | ||
|
|
d12bf41021 | ||
|
|
ca3a584100 | ||
|
|
47d0856296 | ||
|
|
a828d75248 | ||
| edc769ca79 | |||
| 0a22f01587 | |||
| 45f0d571d6 | |||
|
|
880adf7c69 | ||
|
|
591b4bf119 | ||
| 0500557dca | |||
| 654a3829c6 | |||
|
|
2db65776b1 | ||
|
|
7742bd56f8 | ||
|
|
3159208a0a | ||
| fccafba438 | |||
| 8cd4cfb36d | |||
|
|
971b2034ee | ||
|
|
f17d171231 | ||
|
|
4be008382f | ||
|
|
1ae1703f53 | ||
|
|
340227d9a6 | ||
|
|
fb99e83b2d | ||
|
|
8fa76c6732 | ||
|
|
1637db2fe3 | ||
|
|
7e55b1f85e | ||
|
|
575d1492ad | ||
|
|
a043db2de5 | ||
|
|
d3ee0e5f4f | ||
|
|
484a8d1d93 | ||
|
|
7839ac3322 | ||
|
|
e16f494cf4 | ||
|
|
6fc22784b8 | ||
| 52bafa95e3 | |||
| 377c86e390 | |||
| 79abe93744 | |||
| f580955c97 | |||
| 6a625ed4ea | |||
| 8a47d9f3da | |||
| 148b6492ea | |||
| be3fa7a704 | |||
| 63af2daf28 | |||
| 37be3a1759 | |||
| df2547ff81 | |||
| 7693de93dc | |||
| c061045466 | |||
| abd68f2dc8 | |||
| 285f956caa | |||
| 019cf4adf4 | |||
| cf38e7253f | |||
| d809362ea7 | |||
| c08987a781 | |||
| e60c3d7aa3 | |||
| 614b8d0948 | |||
| 8834b906f4 | |||
| 828a022768 | |||
| 26c8d08d04 | |||
| 68a9b2281a | |||
| 63df493d33 | |||
| b7110c80b5 | |||
| c4dbd10a85 | |||
| 041a407978 | |||
| f73c997c38 | |||
| db2a955dea | |||
| a91643d2ec | |||
| 269cf7ea03 | |||
| e3aa964db8 | |||
| fa2fa66d4a | |||
| 6d2a189fef | |||
| 2033f61c7e | |||
| 4e2222966f | |||
| fbe9dc87e9 | |||
| d6f078ab60 | |||
| a940863799 | |||
| 11ffa66851 | |||
| fc3fa22bee | |||
| 37ff60fcfb | |||
| d2d5eebe12 | |||
| 9cfb5aa344 | |||
| 5e7f898840 | |||
|
|
6d3253aed3 | ||
|
|
52e5f246ce | ||
|
|
6222377bc5 | ||
|
|
2d10f57643 | ||
|
|
5f27a95498 | ||
|
|
7fdf832f44 | ||
| 43d2f83677 | |||
| e882a15aa0 | |||
| 1a3f16119b | |||
| 8e2e515af3 | |||
| f1a2495431 | |||
| c66b794daa | |||
| b9f7ea2722 | |||
| 455e17d4b1 | |||
| a1a6a78dac | |||
| 07f91aef74 | |||
|
|
079ab4d98f | ||
|
|
6e53bc3ca5 | ||
|
|
5e8eb716b1 | ||
|
|
34ee8fa11d | ||
|
|
b7dc95af26 | ||
|
|
297391d57e | ||
|
|
aff870fba7 | ||
| 7b1ac47228 | |||
| 7eb9abbdb5 | |||
| 521bd5071a | |||
| ab7e1705c4 | |||
|
|
a2390a6ab2 | ||
|
|
8dc5dcb1bd | ||
|
|
5d010d2f77 | ||
|
|
cec5544472 | ||
|
|
5f79c3276a | ||
| aadb717c9f | |||
| e2e9201fdd | |||
|
|
9053bdf10c | ||
|
|
b14297d1af | ||
|
|
e90979bbdc | ||
|
|
e02c278e7a | ||
|
|
e60d9483a3 | ||
|
|
ba49312fd5 | ||
| ba3c98771f | |||
| 4c738cc61d | |||
| d648a79ec4 | |||
| c325927418 | |||
| dba5625446 | |||
| 91189968e9 | |||
| 433d8a460e | |||
| ec9857fe73 | |||
| a9b01566e1 | |||
|
|
a384aba4df | ||
| e587ad3ca1 | |||
|
|
6a7c8b3d28 | ||
|
|
6f52c956ec | ||
|
|
9e5d2f47e2 | ||
|
|
627f264ef3 | ||
|
|
464de4ee5a | ||
|
|
cf76235123 | ||
| 8d9f51f50f | |||
| d840185ec7 | |||
| 9f4ab20b9d | |||
| 0877ff8f66 | |||
| 78046e8707 | |||
|
|
9fb8bc989d | ||
|
|
3c89670dae | ||
| 21b73d55f7 | |||
| 9199cdf7e2 | |||
|
|
8589216a77 | ||
|
|
87768c6b53 | ||
|
|
ca320f4334 | ||
|
|
7697ab59fa | ||
| e5e6f360dc | |||
| 68a9462714 | |||
| b185a94fcc | |||
| 708280ca14 | |||
| 0ab1e7eef7 | |||
| c7b1d46b18 | |||
| 9357a62f0c | |||
| c5b25e9a16 | |||
| a35d057146 | |||
| 7fc495eec9 | |||
| 46f37942d2 | |||
| e75196c904 | |||
| bdfa249c2e | |||
| d0e5f7da61 | |||
| d8320ba83d | |||
| 23460800d6 | |||
| 58c8b644bc | |||
| c4c04aecb6 | |||
| bb7c98c094 | |||
| dcdb0d06c4 | |||
| b6a66bed41 | |||
|
|
5f277ed815 | ||
|
|
845a553097 | ||
| 74f89c8b2d | |||
| cff8227228 | |||
| 51e2c9af02 | |||
| cd89a77189 | |||
| ab303cfeef | |||
|
|
07004a7415 | ||
|
|
d2069a3e7f | ||
|
|
501cee0057 | ||
| ac2454fd0e | |||
| 931a4cf807 | |||
| cb7099264e | |||
| e7aa951e89 | |||
| ef70598180 | |||
| 698fca8787 | |||
| 2f86090f21 | |||
| 2988a3b34e | |||
|
|
4fe5f65867 | ||
|
|
4bb1953d4a | ||
|
|
57a8260f03 | ||
| e4936a23bc | |||
| 9f37cb3f8d | |||
| b128b2436d | |||
| 66158e94dd | |||
| f6b489d950 | |||
| 30312caf82 | |||
| 1d0dd65f5e | |||
|
|
0b245f62af | ||
| 50d90af3a5 | |||
|
|
49b8585522 | ||
|
|
b49f098a5e | ||
| e9a15b950e | |||
| ee676614f8 | |||
| 710abf2323 | |||
| 1a9f06d259 | |||
|
|
eaaa99a946 | ||
|
|
c8e4d624b7 | ||
| f08e36d100 | |||
| de73536d1c | |||
| 6a861305d6 | |||
|
|
367fa130c0 | ||
|
|
d04987a3e2 | ||
| b0fa185d36 | |||
| 094718e67f | |||
| e4a8bf80e9 | |||
|
|
c04b102a81 | ||
|
|
da9b3a04b4 | ||
|
|
234a030801 | ||
|
|
5ea8e851d7 | ||
|
|
afeeef4af7 | ||
| ee1e2f8556 | |||
| 1157b41730 | |||
| ca4d75c63f | |||
| f45bd7acc4 | |||
| 7bdd62d4a9 | |||
| b01ee9129b | |||
|
|
214c93923c | ||
|
|
bfa1d67b5c | ||
| a0a1a1a06a | |||
| 468ad385d7 | |||
| fa94667c0f | |||
| c997fbf1cb | |||
| 7283ace072 | |||
|
|
69743d4ef0 | ||
|
|
e033671ffb | ||
|
|
15cde37af7 | ||
|
|
7fb74bc7d8 | ||
| 43968995ea | |||
| 0574180e4b | |||
| 5b653272ee | |||
| d28a6051f1 | |||
| f9063ad26e | |||
| 2f4d060ca3 | |||
| fcd0cf4836 | |||
| 26f50c2acb | |||
| c3eb1fc78c | |||
| b15cc542e1 | |||
|
|
ec094d7471 | ||
|
|
3dc432131c | ||
|
|
1a19604163 | ||
| fdebb2b215 | |||
| 7d8f047087 | |||
| bf8af41f3f | |||
|
|
cdf29d2b0d | ||
|
|
7194049127 | ||
|
|
e34cec812f | ||
|
|
11a5b53d2a | ||
| efe22de0a0 | |||
|
|
82f7571612 | ||
|
|
2ac54a50ec | ||
| 5dd1e10b61 | |||
| e9e8e87719 | |||
| 3c0fa205d1 | |||
| 47ca7bde41 | |||
|
|
9e28d579d1 | ||
|
|
1c96522447 | ||
|
|
1a568621ca | ||
| eecefee674 | |||
| ea0332851d | |||
| a25a7dc023 | |||
|
|
b4fe1ca199 | ||
|
|
b315ae5644 | ||
|
|
f7113601f3 | ||
|
|
8d6e3e9644 | ||
|
|
23b864d378 | ||
|
|
be1119be6f | ||
|
|
b836e7fd67 | ||
| a237b4041d | |||
| ea4cd29723 | |||
| 13397fa1f7 | |||
| 2fab472150 | |||
| 8c71b4845a | |||
| b70f909a32 | |||
| 1b15aed6a2 | |||
| 5019fbd3fc | |||
| 2ea19dcf03 | |||
| 4d756d5624 | |||
| f6f759110f | |||
| 8d27b5b51e | |||
|
|
9f064609e7 | ||
|
|
fd10d4dbc4 | ||
|
|
fadb5faf0d | ||
| e5e514b522 | |||
| 74e6d5a1da | |||
| 3cf0570912 | |||
|
|
8da51a0a82 | ||
|
|
37ff7fbb91 | ||
|
|
8c20b51e13 | ||
| 391a28d659 | |||
| 4535fb7dfb | |||
| 546d1b4c44 | |||
| 5fe605c130 | |||
| 4408c0ecc6 | |||
| 49f08d1191 | |||
| 903bafb245 | |||
| 59b02b3f28 | |||
| 4a23e33080 | |||
| 1e1b06fc48 | |||
| 7c56d2bf4e | |||
| 4add0a806c | |||
| c9bb7fe502 | |||
| a8a7a129c9 | |||
| c3c5532cb5 | |||
| 78bfc16287 | |||
|
|
6c6162df74 | ||
|
|
a837aff0fb | ||
|
|
f673afc7fc | ||
|
|
0ea96c728c | ||
|
|
77e71e3296 | ||
|
|
ce870b9acf | ||
|
|
7f889b54e0 | ||
|
|
ebd596d0d2 | ||
| 04ce95caa4 | |||
| 29bf172187 | |||
|
|
41619febb9 | ||
|
|
0f4b769d49 | ||
| 66cd8217b9 | |||
| e684c4e547 | |||
| c439f41d69 | |||
| 823e96b014 | |||
| 0cca24ee30 | |||
| 66cccd0867 | |||
| 463ddf3cb2 | |||
|
|
f0e0987f31 | ||
|
|
16bea58ab5 | ||
|
|
f2bbbaaeb6 | ||
|
|
5098f6f4a1 | ||
|
|
bc1815ae1b | ||
| 6256c90958 | |||
| f0bfe249e0 | |||
| 7bbfd7c506 | |||
| 3c7cbe28a1 | |||
| c834aacf3a | |||
| 90b0ef41e3 | |||
|
|
2aeeec4468 | ||
| a7c5723e10 | |||
|
|
ba595b9d2c | ||
|
|
d9118aaf93 | ||
| 1bdc71998b | |||
| a597f7a67a | |||
| 195964ef5a | |||
|
|
c27ca77717 | ||
|
|
7d0d460e5c | ||
| 5ac9df3056 | |||
| b8d64f1f28 | |||
| c8dd9664be | |||
| 8899a3a6bb | |||
|
|
67f56f9b84 | ||
|
|
fd12b9e571 | ||
| fb329c94aa | |||
| 16d06582ee | |||
|
|
6f98f111dd | ||
|
|
51a1c1d8e1 | ||
|
|
8445c23984 | ||
| 961f8f874e | |||
| 283b6244b1 | |||
| f19a15dbe8 | |||
| 791d44df02 | |||
|
|
28e67db78d | ||
|
|
63a120c652 | ||
|
|
f60cabbbc0 | ||
| 06db759749 | |||
|
|
373608d989 | ||
|
|
45e3dde03f | ||
|
|
3625180a6e | ||
| aae1442a6f | |||
| 08dcd03468 | |||
|
|
deda511e32 | ||
|
|
9bcf615b4b | ||
|
|
70912c4c43 | ||
|
|
fa013c1974 | ||
| 11fbeb1ed0 | |||
| f432b8cce6 | |||
|
|
05ddd33bcd | ||
|
|
9f5c901502 | ||
| 33d5d3a2ea | |||
| 2668dd3c47 | |||
| 2bc5fef175 | |||
| ea92e1f20d | |||
| 9f1cf1d90e | |||
| b43f9baead | |||
|
|
41ffe335fc | ||
|
|
56d0dcd25f | ||
|
|
4304acbe6f | ||
| 2f1b22d423 | |||
| 3eb8626831 | |||
| 5a86f2e649 | |||
| 93e9c61943 | |||
|
|
c5e9941adb | ||
| 56679808e9 | |||
|
|
40f5705e7a | ||
|
|
32975d9900 | ||
|
|
72db49e7f5 | ||
|
|
472f5e65b4 | ||
| e2f8fb082c | |||
| a47e53b19e | |||
| c01acec9e6 | |||
| 969d7586fc | |||
| 31a40ff7ca | |||
| afb9c99228 | |||
| 8ee6a529a0 | |||
| cebc05d132 | |||
| d23ac82b1b | |||
| e86b576050 | |||
| 8a774aa328 | |||
| c5da68dc47 | |||
| 28df672a7d | |||
| 203c88dd70 | |||
| fa86a2af45 | |||
| ac28ba233c | |||
|
|
47dc2bfc6e | ||
| 085dac0630 | |||
| 7b27b1362d | |||
| 704e3c25bf | |||
| 7e5b10aab3 | |||
| 3ccbd8f905 | |||
| 89a234e77d | |||
| 388dd54bfa | |||
| 035c4412f1 | |||
| d4eb7c846b | |||
| fef50d7a37 | |||
| e5a95972a5 | |||
|
|
36a796b38b | ||
| 94927ae0a4 | |||
| 4d7153661c | |||
| 76062136d6 | |||
| ea4ba74989 | |||
|
|
5a09d7a195 | ||
|
|
e0332b9ddf | ||
|
|
685ba09f7d | ||
|
|
7aa1fc0342 | ||
|
|
653264151a | ||
|
|
fada00c738 | ||
| a10d30337a | |||
| 85ffed114b | |||
| 1093ac68b6 | |||
| 71e6abd816 | |||
| 00c948116e | |||
| b6efd598bd | |||
| bfe7ad4aa6 | |||
| 018ccef46a | |||
| feb836f849 | |||
| 0106f21b86 | |||
| 1b5f64785d | |||
| 77a4aee88e | |||
|
|
ce1e2f3eab | ||
|
|
75fbd2844b | ||
|
|
832f331603 | ||
| 9a2d58d922 | |||
|
|
34c4cd47ef | ||
| c46f65600f | |||
| 56ebcfbce2 | |||
| aa1eb7411e | |||
| 4626ea3c55 | |||
| 5858f7dcf1 | |||
| 440dfdcceb | |||
| 36e41ecd89 | |||
| e1b08a9979 | |||
| b9041d9c09 | |||
| 037a0d12ff | |||
| 956b72729f | |||
| 9b185e6919 | |||
|
|
f77de3a1f4 | ||
| f03d32030d | |||
|
|
6a098ffa13 | ||
|
|
12c10167f1 | ||
|
|
679b213b6f | ||
|
|
6fa6c38398 | ||
| 925da9fa03 | |||
| 8f0d45adf9 | |||
| 505288fdb7 | |||
| 44e045ece3 | |||
| 429fdad2b7 | |||
| 46fbbd747e | |||
| 803bdfd291 | |||
|
|
6cbc4882fa | ||
|
|
54f8d4b5e0 | ||
|
|
314ad7a4f8 | ||
|
|
a56510c35a | ||
|
|
c2e2140ce6 | ||
| 83915d332f | |||
| 751aeb785d | |||
| 7cadab9345 | |||
|
|
8a7b64dd65 | ||
|
|
4c598200e5 | ||
|
|
d052918725 | ||
|
|
8fd6a3462e | ||
|
|
11eb6595dd | ||
|
|
0adfcb745d | ||
|
|
779e1e8be3 | ||
|
|
5297880c3b | ||
|
|
6028ef8cdd | ||
|
|
c7de1779bd | ||
|
|
95bfb00a9d | ||
|
|
5fc50f2d96 | ||
|
|
22d7395e11 | ||
|
|
3d4ea89516 | ||
|
|
2ed63cafd0 | ||
|
|
701652c6b2 | ||
|
|
df66b51e5c | ||
|
|
0c6187a759 | ||
|
|
2d6867b729 | ||
|
|
0b8d0a1843 | ||
| 64c7b8c1fd | |||
|
|
42f1d47f82 | ||
|
|
9ca0cd7c43 | ||
|
|
4c187d1fbd | ||
|
|
733de89883 | ||
|
|
0e1a5a70df | ||
| 5ecebd5117 | |||
| c6626b230a | |||
|
|
1cab7332f9 | ||
|
|
c1d88943a9 | ||
| bc85e561d2 | |||
|
|
be8968605b | ||
| 569c2e719f | |||
|
|
5fa7e36dc2 | ||
|
|
4a533b3cf0 | ||
| d2129459fe | |||
|
|
9784d07680 | ||
|
|
a71fa4df51 | ||
|
|
ce384dbba9 | ||
|
|
dd8f5696a2 | ||
|
|
4211bce256 | ||
|
|
bc240cd2ee | ||
|
|
f869f8eb10 | ||
|
|
9b438c78a3 | ||
| a5b435b80f | |||
| a64d4e30de | |||
| 0759452381 | |||
|
|
58a78a5366 | ||
|
|
9bd695a24d | ||
| e614e3a07a | |||
|
|
8c65592394 | ||
|
|
e093d694fd | ||
|
|
a5bfc4e41d | ||
| be001477ce | |||
| 3e150b2067 | |||
| 8ea06c05e9 | |||
|
|
9b589eece6 | ||
|
|
ba4388b87d | ||
|
|
5b3a668ce7 | ||
| aacbe92cdc | |||
| 57ab6c64ef | |||
| ffaef2ff6c | |||
| 5113cb0606 | |||
| 30d5466805 | |||
| 8457a61ded | |||
| e7f9b77fe5 | |||
|
|
6c0f65b801 | ||
|
|
ad1fa0e4c2 | ||
| 227c742f0d | |||
| c317942447 | |||
|
|
a6f02bf22f | ||
| 4f12aa92b6 | |||
| e6a2ce2b69 | |||
|
|
1f0439c7f9 | ||
|
|
676ef74bdc | ||
|
|
b2bc47da99 | ||
|
|
02787db0a1 | ||
| 19524520f4 | |||
| 2a2c4b1d39 | |||
| 257c99698e | |||
| 8ff8a7480f | |||
| 5e1ff16052 | |||
| dbd89798d5 | |||
| b5b6f737aa | |||
| 1d60a6a129 | |||
| 0017568cc7 | |||
|
|
375f717721 | ||
|
|
18914bea7e | ||
| fc48d8931f | |||
| 619d33b412 | |||
| 1a48527c70 | |||
|
|
ee68a5d782 | ||
|
|
3a29d25060 | ||
| 77f514a03b | |||
| 954f6207ec | |||
| 891f6fb15f | |||
| 49b086ad10 | |||
| 86e7119cfb | |||
|
|
775ae3266c | ||
| 1aea8e93f2 | |||
| 804dc9b1b4 | |||
| bd543e56d5 | |||
|
|
3dc7866fba | ||
|
|
ffd371e5b4 | ||
|
|
40aad9d1a3 | ||
| 709393a9a6 | |||
| fb8de15eca | |||
| f4e9a3474a | |||
|
|
890389843f | ||
| db04267591 | |||
| 5ff2bf11d7 | |||
| 76618de386 | |||
| eda92b3f0b | |||
|
|
b1b4b4147c | ||
|
|
4ba5f63a62 | ||
|
|
8b274b2822 | ||
| 54cbaf4b80 | |||
| c688af01f2 | |||
|
|
37de7d9276 | ||
|
|
02b3a407a9 | ||
| 5ebf0669f5 | |||
|
|
031d71bf99 | ||
|
|
205f0d54c5 | ||
|
|
50e46fed02 | ||
|
|
1303b1805a | ||
|
|
2845c2c8b9 | ||
|
|
cd817dbf57 | ||
| f9ce559915 | |||
| e40401f61f | |||
|
|
6e64eb741a | ||
|
|
c4a37f5d73 | ||
|
|
8f5a86db0b | ||
|
|
14c99f6c6b | ||
|
|
bf072e35f5 | ||
|
|
b8048704ba | ||
|
|
b6704c3caf | ||
|
|
6b07c84c80 | ||
|
|
980e1547cd | ||
|
|
ae2191f369 | ||
|
|
4b1a58c036 | ||
|
|
4dbd5a1fad | ||
|
|
b063cad764 | ||
|
|
f1eb48ae74 | ||
|
|
7233540ab4 | ||
|
|
e634481113 | ||
|
|
b3591f879d | ||
|
|
12c447d6b0 | ||
|
|
c73876e8b0 | ||
|
|
a726ceca59 | ||
|
|
51db8b4ec2 | ||
|
|
9f4dbda152 | ||
|
|
8e1766eed0 | ||
|
|
f1d67f2f7d | ||
|
|
ebb6577e98 | ||
| bc85e33074 | |||
| 5318e5d32a | |||
| 2aabb2347b | |||
| 3790b8ee72 | |||
| f4766d4ab4 | |||
| d1fab003d2 | |||
| 718198bcfe | |||
|
|
7b83f42ed8 | ||
| f23f4133d0 | |||
|
|
fb29310ba1 | ||
|
|
b86f168fe8 | ||
| 6fa0ab30db | |||
| d41bc284d4 | |||
| e2697aa407 | |||
| ae937dbf65 | |||
|
|
8da24f4933 | ||
|
|
b1486c3901 | ||
| ffeaac8c46 | |||
|
|
a54f7e7c30 | ||
| d1e45de91e | |||
| 988fe89576 | |||
| 18f9e9130c | |||
| 5f0546c6cf | |||
|
|
de865b918f | ||
|
|
d2e917e3ce | ||
|
|
e70580c388 | ||
| 783754e0c7 | |||
| 856c6e1be9 | |||
| 1accfc087a | |||
| 9627239f9a | |||
| 518a6c0748 | |||
| 6d9efc1509 | |||
| 3afd67e680 | |||
| c44fc14796 | |||
| 93b3cd9660 | |||
| ff628dc680 | |||
| 1e09508efb | |||
| 2882b06128 | |||
|
|
e7d4e98ad0 | ||
|
|
c8f4d82bf5 | ||
|
|
0d84a9214e | ||
|
|
c661f4a871 | ||
| c31a4bcd8f | |||
| ff842c5443 | |||
| d000eaa6b8 | |||
| 3114d3cb36 | |||
|
|
7454e16076 | ||
|
|
c3ae729466 | ||
|
|
faeb59bae5 | ||
|
|
5a69a770ac | ||
|
|
d1772be737 | ||
| 19d170c1bf | |||
| 825439255b | |||
| a749c5dd2e | |||
|
|
e62f54a975 | ||
| 540d2a4e28 | |||
| e832d5e4d4 | |||
| 3be1bf3c14 | |||
| d2076a81d5 | |||
| 874f73e933 | |||
| 8856f7fc7a | |||
| 9f23df04db | |||
| 896120fea4 | |||
| 074e4154ac | |||
| 8d330e8ad9 | |||
| c73414a1f4 | |||
| 050b93d47a | |||
| 75a63c7a6f | |||
| 1d443b140b | |||
| 754de78b57 | |||
|
|
109176b8bd | ||
|
|
6f687b5ce0 | ||
|
|
66047c541d | ||
|
|
160c403005 | ||
|
|
92ab7edc10 | ||
|
|
95aee1daae | ||
| e7fbaf8924 | |||
|
|
a744a3cb3d | ||
|
|
782a4f9976 | ||
| 5cd3121546 | |||
| 8d77cd0be6 | |||
| 165f0301f0 | |||
| 784f599e38 | |||
| 7d967ed41e | |||
|
|
737ec594fd | ||
|
|
b2d615f31a | ||
|
|
bdbf5b4648 | ||
|
|
3be72dbe49 | ||
|
|
1d71d276bb | ||
|
|
54fe254ab0 | ||
| d79fe65bf1 | |||
| 4bf4dc2588 | |||
| edaa4344be | |||
| 54df4a0ae2 | |||
| 3662ed3f96 | |||
| d411b428f8 | |||
| 305324fe1a | |||
| bf05f88c00 | |||
| e84d800ba0 | |||
| a016f16052 | |||
| ee96759832 | |||
|
|
db68ce7d1b | ||
|
|
87d8a92cdd | ||
|
|
471cdd866b | ||
|
|
6e191413b9 | ||
| e28502a00c | |||
| 7f8c84bd35 | |||
| f8996999d4 | |||
|
|
10b3637c80 | ||
|
|
22330b674a | ||
|
|
6bb99194bd | ||
|
|
43ec55dfb6 | ||
|
|
8fe468fda2 | ||
|
|
4e4ed0f66c | ||
|
|
002a47c169 | ||
|
|
258ddbab31 | ||
|
|
703201dae6 | ||
|
|
66e10a5a80 | ||
|
|
f8d468d55b | ||
|
|
ca70371585 | ||
|
|
68f6ae2a8d | ||
|
|
7803decb29 | ||
| 35fbd4d865 | |||
| 2a73986e64 | |||
|
|
4e2e1affa8 | ||
|
|
9bae02406c | ||
|
|
a4f36a2fd5 | ||
|
|
fda2a3120b | ||
| 87580cfece | |||
| 318d0a1441 | |||
| 874a59ea04 | |||
| a7c60a932a | |||
| 7f33597c02 | |||
| 92dafd74c9 | |||
| 9b55083768 | |||
| c646a8adb0 | |||
| 69fe927576 | |||
| f4a80a4486 | |||
| 83058acfea | |||
| 8f832ec441 | |||
|
|
5e1573ae09 | ||
|
|
f1176dfefb | ||
|
|
12cd9e8f1f | ||
|
|
81c5d7ee65 | ||
|
|
878b5a129c | ||
| 821a3420ae | |||
| bee78cc9a2 | |||
| 5975519c39 | |||
| ec9b60e1d6 | |||
| 9e653595a9 | |||
| 02d65b4fb2 | |||
| 533b54a768 | |||
|
|
5c2c9f22ce | ||
|
|
98d98b1131 | ||
|
|
7386f4427d | ||
|
|
9a5ee2b264 | ||
|
|
a5cbca8d74 | ||
|
|
2b2fb4319a | ||
|
|
0afcf92582 | ||
|
|
33a096e382 | ||
|
|
ee2a8ac3ce | ||
|
|
17e7ebc8fe | ||
|
|
41919c44c9 | ||
|
|
12190f88c8 | ||
|
|
c74c7376cc | ||
|
|
4f68fbcff1 | ||
|
|
e539a931f9 | ||
|
|
abcad626f6 | ||
|
|
ae6692523b | ||
|
|
3a2253f1ce | ||
|
|
4380f0bc5b | ||
|
|
18d0d55d4f | ||
|
|
f047ca0324 | ||
|
|
f02988a0a7 | ||
| fc4dcd41ae | |||
|
|
d4a7fa441c | ||
|
|
5af86c28f1 | ||
|
|
62e6f8b77d | ||
| 4c0dd27332 | |||
| aa270b5f7d | |||
| e90c4f7239 | |||
| c35a188abb | |||
| 65bed9dada | |||
| 1d2cb17d54 | |||
| d4568ad740 | |||
| 96858c2cc3 | |||
|
|
6b8e96ec74 | ||
| a9ce35200c | |||
| 164454b5b2 | |||
| 404172e5f2 | |||
| ec39bf9a97 | |||
| 16f590dea5 | |||
| 577dc94850 | |||
|
|
471426e931 | ||
|
|
ed3dcf9ee8 | ||
|
|
c31ecfb1e9 | ||
|
|
449c568907 | ||
|
|
b828c8fcde | ||
|
|
557041335a | ||
|
|
bccb6d7bd2 | ||
|
|
365c04375a | ||
|
|
d8c09f9597 | ||
|
|
90634f73c7 | ||
|
|
c5d540686e | ||
|
|
3452e4c335 | ||
|
|
5d3657bba2 | ||
|
|
393c9ec941 | ||
|
|
5678cccde1 | ||
|
|
067cd9a1af | ||
|
|
1c3692d034 | ||
|
|
2d73f0c414 | ||
|
|
27974e5e7c | ||
|
|
9b4e9c3ee1 | ||
|
|
11e231992a | ||
|
|
8737350002 | ||
|
|
ca2ed7a69c | ||
|
|
a75cdffe59 | ||
|
|
324966b1c6 | ||
|
|
660ee9d437 | ||
|
|
94d6c10522 | ||
|
|
ae49f3f3a7 | ||
|
|
20d8224853 | ||
|
|
fc55a775f8 | ||
|
|
62f9bb3795 | ||
| 1b836175b1 | |||
| fe0a736feb | |||
|
|
547272dfcf | ||
|
|
10e80bfc27 | ||
|
|
748550b670 | ||
|
|
39367f5fb7 | ||
| 74ef15b88e | |||
|
|
ef6c8e85cb | ||
|
|
4e334dca7d | ||
| 474a532f01 | |||
| 6fbcab9351 | |||
|
|
36e488e0aa | ||
|
|
a3ae8401fb | ||
|
|
7a0b6307b0 | ||
|
|
580ebc91ff | ||
|
|
dc325e6ab4 | ||
|
|
80976f45a7 | ||
|
|
5bed3c180b | ||
|
|
67c137392f | ||
|
|
6e979d58a2 | ||
|
|
7a95bce2b1 | ||
|
|
84dd2d7cd9 | ||
|
|
4a8867dbb5 | ||
|
|
8930e64bf7 | ||
| 9405b0d630 | |||
| 71f1a2671e | |||
|
|
71a0a3c06b | ||
|
|
f2a8a82821 | ||
|
|
3b37e8644c | ||
|
|
2832105ac2 | ||
|
|
eafa6daf5b | ||
| 7a309bcb17 | |||
|
|
fc4a59d41a | ||
|
|
11f94ebcb4 | ||
| 7c94bc4826 | |||
|
|
00cf7b3140 | ||
|
|
914910903e | ||
| 28d92c468c | |||
| dd5997fea6 | |||
| d19aa7083b | |||
|
|
858a195e13 | ||
| 4b1974aceb | |||
| eb45f6e7d0 | |||
| 1c8f230a64 | |||
|
|
85b4d674ea | ||
|
|
8c3b658df0 | ||
| 46511fed71 | |||
| f346727469 | |||
| e9844e38a4 | |||
|
|
91012a00b6 | ||
|
|
bd116ff011 | ||
|
|
ce7c6c657b | ||
| 131f46b59e | |||
|
|
0f8f6679ab | ||
|
|
a5d08e700a | ||
| f98f54f3c1 | |||
|
|
23e2c507df | ||
|
|
6331b5d164 | ||
|
|
2dd1ad8a08 | ||
| e45e63103f | |||
|
|
640c9527be | ||
|
|
8fa682e9e8 | ||
| 480eb72be0 | |||
|
|
8dd658f1e9 | ||
| a9c5a5fd2b | |||
|
|
5aa2e2a357 | ||
|
|
ba6588058a | ||
|
|
8b3058513f | ||
|
|
f9b24492c9 | ||
| 2de3a73fef | |||
| 86ab0806fd | |||
| fef71ead79 | |||
| 26a61a44a2 | |||
|
|
4d87164b8e | ||
|
|
81d178b3a4 | ||
|
|
51f3b5b30b | ||
|
|
b4b935c378 | ||
|
|
b0dc1f4763 | ||
|
|
79cff13edb | ||
|
|
b71a1c834d | ||
|
|
24312a8f2b | ||
| a14188ee35 | |||
|
|
59008e7a7e | ||
|
|
3d44ab4a52 | ||
|
|
8c82cef169 | ||
| 4512fb3268 | |||
| 483eea66b9 | |||
| 43b9ba74ab | |||
| c3dfdd6fb8 | |||
| 51548b52ba | |||
|
|
78ce0120c4 | ||
|
|
4e3746cfba | ||
|
|
1f77698bc4 | ||
| 78d41aa2f5 | |||
| be5d60d6c1 | |||
| ae91cac28a | |||
|
|
f80e5ce455 | ||
|
|
db1aed53eb | ||
|
|
7fdacaeb7c | ||
| cd41229f9e | |||
|
|
2b8f970acc | ||
|
|
91993feee8 | ||
|
|
5300cec43d | ||
|
|
9d7cf848e1 | ||
|
|
23b69c1e7b | ||
|
|
7bbca01f86 | ||
|
|
30ff40e84a | ||
|
|
be6795b42a | ||
|
|
a7893d07bb | ||
|
|
7072c8ad2a | ||
|
|
6d99a5fa16 | ||
|
|
98ca270156 | ||
|
|
4b1bf8585d | ||
|
|
1747eb3a59 | ||
|
|
3e3aaa54c4 | ||
|
|
e18a4f78c4 | ||
|
|
f0aa041c1e | ||
|
|
9e5a6cae11 | ||
|
|
94eab51d6c | ||
|
|
ecec69a45e | ||
|
|
5213b03598 | ||
|
|
edce5f3227 | ||
|
|
7b98aa90d9 | ||
|
|
00166b9246 | ||
|
|
9e3c29bd47 | ||
|
|
d9a5b0f326 | ||
|
|
b9d502db42 | ||
|
|
b77a85d134 | ||
|
|
8a3e6833ee | ||
|
|
8ff91be0f0 | ||
|
|
ff34193e02 | ||
|
|
955ebd0904 | ||
|
|
20b68d1f92 | ||
|
|
091c11c951 | ||
|
|
4971f2b96a | ||
|
|
13208fed14 | ||
|
|
ee7820ff8b | ||
|
|
c15ff3f344 | ||
|
|
1056b9b0b0 | ||
|
|
9e58ed47ea | ||
|
|
35e6bb8cd9 | ||
|
|
c6561a4fe8 | ||
|
|
93577cab8e | ||
|
|
211f589d84 | ||
|
|
6d673d6f32 | ||
|
|
09ebb4ca06 | ||
|
|
5dbf76c4e2 | ||
|
|
bcfcb5da12 | ||
|
|
6da1286e56 | ||
|
|
8afec1e962 | ||
|
|
f3fcaa3ed6 | ||
|
|
ebbe39468e | ||
|
|
94809e149d | ||
|
|
6a869cf4b5 | ||
|
|
269b6fa5fb | ||
|
|
c8fe8c27f8 | ||
|
|
008d0d626e | ||
|
|
bb1c56182e | ||
|
|
331490c447 | ||
|
|
ffcbabf62e | ||
|
|
0313149ea5 | ||
|
|
85a815dddc | ||
|
|
77be2c7472 | ||
|
|
8840dfc59d | ||
|
|
2524077768 | ||
|
|
dbc8c7dcf5 | ||
|
|
78678efd5d | ||
|
|
998ad81835 | ||
|
|
d71674393f | ||
|
|
8a04e7a507 | ||
|
|
44a30bf9b5 | ||
|
|
68d28995b8 | ||
|
|
31eb3773f6 | ||
|
|
70055f2f4a | ||
|
|
bedc640e13 | ||
|
|
9fa605f83e | ||
|
|
f18c27fe02 | ||
|
|
201b188579 | ||
|
|
4b28732d32 | ||
|
|
81d20625f5 | ||
|
|
4c11f2e280 | ||
|
|
2b2fd1a72c | ||
|
|
fe2ffcd6a6 | ||
|
|
89d3349b49 | ||
|
|
8720fc5992 | ||
|
|
c3e979e096 | ||
|
|
f76298c42f | ||
|
|
8ad330f690 | ||
|
|
5e70f7ca73 | ||
|
|
0dd765123f | ||
|
|
770e9d1d23 | ||
|
|
381d40c346 | ||
|
|
e3b7304bbf | ||
|
|
6f01397d18 | ||
|
|
95174707d8 | ||
|
|
1ff64e01e5 | ||
|
|
6bbc8e3f1c | ||
|
|
39abb48d6f | ||
|
|
bad3f86d6d | ||
|
|
47df80138b | ||
|
|
6549e2baeb | ||
|
|
3ebb3842c2 | ||
|
|
990a270a7b | ||
|
|
ef4624e1bd | ||
|
|
65c84ae5b5 | ||
|
|
839c6baa8a | ||
|
|
d8f55a4cc4 | ||
|
|
85a0595f2a | ||
|
|
e3309e9841 | ||
|
|
278ef4e9c8 | ||
|
|
879703e870 | ||
|
|
e5beab268c | ||
|
|
0232df535e | ||
|
|
bd5ca604f4 | ||
|
|
9e2f4f75c1 | ||
|
|
ffb6a2c9c7 | ||
|
|
d1cdef3be5 | ||
|
|
b38754cf74 | ||
|
|
9c162f7ab8 | ||
|
|
5302e791b9 | ||
|
|
8229ec7dc0 | ||
|
|
b1cd767f9c | ||
|
|
2d8672e0a8 | ||
|
|
ad30fdcc5d | ||
|
|
2cd94fd026 | ||
|
|
b1d7df2d48 | ||
|
|
e6a72b6a32 | ||
|
|
7bc0ddd068 | ||
|
|
84c45cb550 | ||
|
|
4a803d90f2 | ||
|
|
555c3cf0dd | ||
|
|
0f4a51af18 | ||
|
|
7d8c3ca8f3 | ||
|
|
1f463aeaaa | ||
|
|
26f4566fac | ||
|
|
37be900b22 | ||
|
|
e7ea5c2a2a | ||
|
|
b18e8eb09f | ||
|
|
935dedcf09 | ||
|
|
8893ef0039 | ||
|
|
75c1d4dee1 | ||
|
|
6eb4f997c3 | ||
|
|
3abb07cb3b | ||
|
|
b6e33668ec | ||
|
|
e8cbe6f244 | ||
|
|
e8760df88f | ||
|
|
fa44552437 | ||
|
|
61e9888ab9 | ||
|
|
d8d167baa8 | ||
|
|
30ba1d1d71 | ||
|
|
dac556a4ba | ||
|
|
9877a5240f | ||
|
|
907184d2eb | ||
|
|
9d1d555032 | ||
|
|
54bbf0b9b3 | ||
|
|
7a1652ac60 | ||
|
|
a9f24e8fe5 | ||
|
|
abecb54b1d | ||
|
|
a5a70884b8 | ||
|
|
f661271f48 | ||
|
|
c1c1687e8e | ||
|
|
1ef079a1f9 | ||
|
|
9bf7bba29c | ||
|
|
7daa3dc004 | ||
|
|
4068a64c54 | ||
|
|
b560deb1f3 | ||
|
|
edc4947280 | ||
|
|
b46a1815e5 | ||
|
|
9c3ab437fb | ||
|
|
3620a0a895 | ||
|
|
0893af46dd | ||
|
|
2ad61ff618 | ||
|
|
00fcdf9cbf | ||
|
|
6dc61dd452 | ||
|
|
9e7ed913ce | ||
|
|
db502aaef5 | ||
|
|
114b78bdfa | ||
|
|
0103b0c814 | ||
|
|
fd5e47ecdc | ||
|
|
ee32111599 | ||
|
|
612fb61ac1 | ||
|
|
b9abb2dd8f | ||
|
|
0931923d0b | ||
|
|
1959e3b7ff | ||
|
|
0a3487a3db | ||
|
|
b0095e26a7 | ||
|
|
f026a9b929 | ||
|
|
7356a0a3c4 | ||
|
|
8a3c42ac0e | ||
|
|
255529c8bc | ||
|
|
02d658dd0d | ||
|
|
55e32d2fe7 | ||
|
|
b2e3347a92 | ||
|
|
11fdeebe76 | ||
|
|
dcd4ce584c | ||
|
|
e1b3c20131 | ||
|
|
1870996244 | ||
|
|
ba96d52611 | ||
|
|
e0d8d14235 | ||
|
|
d6e74883b9 | ||
|
|
20f5a3eda2 | ||
|
|
7e6047ddf7 | ||
|
|
49b62d3733 | ||
|
|
d3530f0af9 | ||
|
|
3f90715e00 | ||
|
|
0115759563 | ||
|
|
8478de460a | ||
|
|
cbb5145123 | ||
|
|
7269c19aab | ||
|
|
3afe1c715d | ||
|
|
aef2bb7457 | ||
|
|
eb2ef0f39d | ||
|
|
00803692b2 | ||
|
|
a543dde9a7 | ||
|
|
d418df3c60 | ||
|
|
88b526f1c4 | ||
|
|
206f365ff3 | ||
|
|
778bb9534d | ||
|
|
305b932cbd | ||
|
|
146101eec4 | ||
|
|
9ba7049438 | ||
|
|
01cdbf99f9 | ||
|
|
e007d2353e | ||
|
|
cf771a5b77 | ||
|
|
dc9957accf | ||
|
|
a08300f095 | ||
|
|
7a6d70c2cf | ||
|
|
03f8f9a6cf | ||
|
|
41111bc0e4 | ||
|
|
15bbe55182 | ||
|
|
2ed7435120 | ||
|
|
3c6ea5523c | ||
|
|
5d482365cd | ||
|
|
165449084b | ||
|
|
1201f57291 | ||
|
|
de0d8bc459 | ||
|
|
90edb573d9 | ||
|
|
2d924ca1e6 | ||
|
|
89b237215a | ||
|
|
9f8acf375c | ||
|
|
349306a1be | ||
|
|
b13feb8f1f | ||
|
|
457f196c79 | ||
|
|
c5e5b51852 | ||
|
|
5b41b51859 | ||
|
|
11e9ff4e2c | ||
|
|
15c787bea1 | ||
|
|
7dbd9453f8 | ||
|
|
f2cca64353 | ||
|
|
b6ad019dec | ||
|
|
efdaa75be0 | ||
|
|
677bd53842 | ||
|
|
751715100f | ||
|
|
b0649b4c09 | ||
|
|
68146d62f4 | ||
|
|
31c2bb06fc | ||
|
|
c6ba7b13c1 | ||
|
|
01743f4218 | ||
|
|
4e4623cdda | ||
|
|
dcf2f6623b | ||
|
|
04f53231c1 | ||
|
|
68d4bde1b8 | ||
|
|
9a5eae70ce | ||
|
|
3343066daf | ||
|
|
4f268a2acc | ||
|
|
c2242ff7fa | ||
|
|
60ae1e3849 | ||
|
|
7e9fdca250 |
176
.gitea/workflows/develop_build_manual.yaml
Normal file
176
.gitea/workflows/develop_build_manual.yaml
Normal file
@@ -0,0 +1,176 @@
|
||||
name: 手动 AiDA back-java 开发分支构建部署
|
||||
on:
|
||||
workflow_dispatch:
|
||||
|
||||
jobs:
|
||||
build_and_deploy:
|
||||
runs-on: ubuntu-latest
|
||||
outputs:
|
||||
build_status: ${{ job.status }}
|
||||
build_url: ${{ gitea.server_url }}/${{ gitea.repository.owner.name }}/${{ gitea.repository.name }}/actions/runs/${{ gitea.run_id }}
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
packages: write
|
||||
|
||||
env:
|
||||
REMOTE_DEPLOY_PATH: /workspace/workspace_aida/DevelopVersion/develop-version-aida-back
|
||||
|
||||
steps:
|
||||
- name: 0.记录开始时间
|
||||
id: build_start_time
|
||||
run: echo "current_time=$(TZ='Asia/Hong_Kong' date '+%Y-%m-%d %H:%M:%S %Z')" >> $GITHUB_OUTPUT
|
||||
|
||||
- name: 1.检出代码
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
ref: dev/3.1_release_merge
|
||||
|
||||
- name: 2.Set up JDK 21
|
||||
uses: actions/setup-java@v5
|
||||
with:
|
||||
java-version: '21'
|
||||
distribution: 'temurin'
|
||||
|
||||
- name: 3.设置JAVA Maven 环境
|
||||
run: |
|
||||
# 适配root/普通用户
|
||||
SUDO=""
|
||||
[ "$(id -u)" != "0" ] && SUDO="sudo"
|
||||
|
||||
# 安装依赖
|
||||
$SUDO apt update && $SUDO apt install -y wget tar --no-install-recommends
|
||||
|
||||
# 下载Maven
|
||||
MAVEN_VERSION="3.9.11"
|
||||
MAVEN_TAR="apache-maven-${MAVEN_VERSION}-bin.tar.gz"
|
||||
MAVEN_URL="https://archive.apache.org/dist/maven/maven-3/${MAVEN_VERSION}/binaries/${MAVEN_TAR}"
|
||||
wget --no-verbose -O /tmp/${MAVEN_TAR} ${MAVEN_URL}
|
||||
|
||||
# 解压+软链接
|
||||
$SUDO tar -xzf /tmp/${MAVEN_TAR} -C /usr/local/
|
||||
$SUDO ln -sf /usr/local/apache-maven-${MAVEN_VERSION} /usr/local/maven
|
||||
|
||||
# 配置PATH
|
||||
echo "/usr/local/maven/bin" >> $GITHUB_PATH
|
||||
export PATH="/usr/local/maven/bin:$PATH"
|
||||
|
||||
# 验证
|
||||
mvn -v
|
||||
|
||||
- name: 4.构建jar包
|
||||
run: |
|
||||
echo "===== 开始构建JAR包 ====="
|
||||
# 新增:打印当前构建分支(两种方式双重确认)
|
||||
echo "当前工作目录分支:$(git branch --show-current)"
|
||||
echo "Gitea检出分支:${{ github.ref_name }}"
|
||||
echo "预期构建分支:dev/3.1_release_merge"
|
||||
echo "========================"
|
||||
mvn -B clean install -DskipTests -Pdev 2>&1
|
||||
# 检查构建是否成功
|
||||
if [ $? -ne 0 ]; then
|
||||
echo "JAR包构建失败!"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
- name: 5.生成Dockerfile
|
||||
run: |
|
||||
echo "===== 生成Dockerfile ====="
|
||||
cat > Dockerfile << 'EOF'
|
||||
FROM openjdk:21-ea-21-jdk-slim
|
||||
VOLUME /tmp
|
||||
RUN ln -sf /usr/share/zoneinfo/Asia/Shanghai /etc/localtime
|
||||
RUN echo 'Asia/Shanghai' > /etc/timezone
|
||||
ADD ./aida-0.0.1-SNAPSHOT.jar /app.jar
|
||||
ENTRYPOINT ["java","-jar","/app.jar"]
|
||||
EOF
|
||||
echo "Dockerfile内容:"
|
||||
cat Dockerfile
|
||||
|
||||
- name: 6.生成docker-compose.yml
|
||||
run: |
|
||||
echo "===== 生成docker-compose.yml ====="
|
||||
cat > docker-compose.yml << 'EOF'
|
||||
version: '3'
|
||||
services:
|
||||
aida_back:
|
||||
container_name: develop-version-aida-back
|
||||
build: .
|
||||
volumes:
|
||||
# 数据挂载
|
||||
- ./log:/log
|
||||
- ./temp:/temp
|
||||
- ./uploads:/temp/uploads
|
||||
ports:
|
||||
- '10090:5567'
|
||||
restart: always
|
||||
EOF
|
||||
# 验证docker-compose.yml生成
|
||||
echo "docker-compose.yml内容:"
|
||||
cat docker-compose.yml
|
||||
|
||||
- name: 7.安装SSH工具
|
||||
run: |
|
||||
$SUDO apt install -y sshpass openssh-client --no-install-recommends
|
||||
# 配置SSH免密
|
||||
mkdir -p ~/.ssh
|
||||
echo "${{ secrets.SSH_KEY }}" > ~/.ssh/id_rsa
|
||||
chmod 600 ~/.ssh/id_rsa
|
||||
ssh-keyscan -H ${{ secrets.SERVER_HOST }} >> ~/.ssh/known_hosts
|
||||
|
||||
- name: 8.同步文件到远程服务器
|
||||
run: |
|
||||
echo "===== 同步文件到远程服务器 ====="
|
||||
# 使用scp同步文件
|
||||
scp -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null \
|
||||
./target/*.jar ./Dockerfile ./docker-compose.yml \
|
||||
${{ secrets.SERVER_USER }}@${{ secrets.SERVER_HOST }}:${{ env.REMOTE_DEPLOY_PATH }} 2>&1
|
||||
|
||||
- name: 9.部署和运行服务
|
||||
run: |
|
||||
echo "===== 开始部署服务 ====="
|
||||
# SSH执行部署命令
|
||||
ssh -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null \
|
||||
${{ secrets.SERVER_USER }}@${{ secrets.SERVER_HOST }} << 'EOF_SSH'
|
||||
cd ${{ env.REMOTE_DEPLOY_PATH }}
|
||||
echo "停止旧容器..."
|
||||
docker compose down || true
|
||||
echo "清理Docker资源..."
|
||||
docker system prune -f
|
||||
echo "构建镜像..."
|
||||
docker compose build --no-cache
|
||||
echo "启动服务..."
|
||||
docker compose up -d
|
||||
echo "验证容器状态..."
|
||||
docker compose ps
|
||||
echo "部署完成!"
|
||||
EOF_SSH
|
||||
|
||||
- name: 10.发送构建结果邮件
|
||||
if: always() # 无论上一步是否失败,都执行此步骤
|
||||
uses: dawidd6/action-send-mail@v3
|
||||
with:
|
||||
|
||||
from: ${{ secrets.MAIL_USERNAME }}
|
||||
# --- 邮件配置 ---
|
||||
server_address: smtp.gmail.com # 替换为你的SMTP服务器地址
|
||||
server_port: 465 # 替换为你的SMTP端口 (通常是465或587)
|
||||
username: ${{ secrets.MAIL_USERNAME }} # 存储在Secrets中的邮箱用户名
|
||||
password: ${{ secrets.MAIL_PASSWORD }} # 存储在Secrets中的邮箱密码
|
||||
subject: 'Gitea Actions 构建通知: ${{ job.status }} - AiDA back-java Develop'
|
||||
# 收件人列表,可以根据需要更改
|
||||
to: 'cgzhou@aidlab.hk,zchengrong@yeah.net' # 替换为实际收件人邮箱
|
||||
|
||||
# --- 邮件正文内容 ---
|
||||
body: |
|
||||
项目: AiDA back-java Develop
|
||||
分支: dev/3.1_release_merge
|
||||
|
||||
🎉 构建结果: ${{ job.status }}
|
||||
|
||||
📅 构建时间: ${{ steps.build_start_time.outputs.current_time }}
|
||||
|
||||
🔗 构建链接: ${{ gitea.server_url }}/${{ gitea.repository.owner.name }}/${{ gitea.repository.name }}/actions/runs/${{ gitea.run_id }}
|
||||
|
||||
# 确保邮件内容为纯文本,或者你可以设置为 html: true 并调整 body
|
||||
content_type: text/plain
|
||||
49
.gitignore
vendored
49
.gitignore
vendored
@@ -1,2 +1,51 @@
|
||||
sql/*.sql
|
||||
|
||||
HELP.md
|
||||
target/
|
||||
!.mvn/wrapper/maven-wrapper.jar
|
||||
!**/src/main/**
|
||||
!**/src/test/**
|
||||
|
||||
### STS ###
|
||||
.apt_generated
|
||||
.classpath
|
||||
.factorypath
|
||||
.project
|
||||
.settings
|
||||
.springBeans
|
||||
.sts4-cache
|
||||
.log
|
||||
|
||||
### IntelliJ IDEA ###
|
||||
.idea
|
||||
*.iws
|
||||
*.iml
|
||||
*.ipr
|
||||
.mvn
|
||||
mvnw*
|
||||
|
||||
### NetBeans ###
|
||||
/nbproject/private/
|
||||
/nbbuild/
|
||||
/dist/
|
||||
/nbdist/
|
||||
/.nb-gradle/
|
||||
build/
|
||||
|
||||
### VS Code ###
|
||||
.vscode/
|
||||
|
||||
### generated files ###
|
||||
bin/
|
||||
gen/
|
||||
|
||||
### MAC ###
|
||||
.DS_Store
|
||||
|
||||
### Other ###
|
||||
logs/
|
||||
log
|
||||
temp/
|
||||
|
||||
docker-compose.yml
|
||||
/src/main/resources/application-local.properties
|
||||
|
||||
@@ -1,2 +1,3 @@
|
||||
# Aida 1.2
|
||||
Version of aida 1.2
|
||||
Version of aida 1.3
|
||||
修改预先登录接口、逻辑
|
||||
192
aida.iml
192
aida.iml
@@ -1,192 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<module org.jetbrains.idea.maven.project.MavenProjectsManager.isMavenModule="true" type="JAVA_MODULE" version="4">
|
||||
<component name="FacetManager">
|
||||
<facet type="Spring" name="Spring">
|
||||
<configuration />
|
||||
</facet>
|
||||
<facet type="web" name="Web">
|
||||
<configuration>
|
||||
<webroots />
|
||||
</configuration>
|
||||
</facet>
|
||||
</component>
|
||||
<component name="NewModuleRootManager" LANGUAGE_LEVEL="JDK_1_8">
|
||||
<output url="file://$MODULE_DIR$/target/classes" />
|
||||
<output-test url="file://$MODULE_DIR$/target/test-classes" />
|
||||
<content url="file://$MODULE_DIR$">
|
||||
<sourceFolder url="file://$MODULE_DIR$/src/main/java" isTestSource="false" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/src/main/resources" type="java-resource" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/target" />
|
||||
</content>
|
||||
<orderEntry type="inheritedJdk" />
|
||||
<orderEntry type="sourceFolder" forTests="false" />
|
||||
<orderEntry type="library" name="Maven: org.springframework.boot:spring-boot-starter-web:2.2.2.RELEASE" level="project" />
|
||||
<orderEntry type="library" name="Maven: org.springframework.boot:spring-boot-starter:2.2.2.RELEASE" level="project" />
|
||||
<orderEntry type="library" name="Maven: org.springframework.boot:spring-boot:2.2.2.RELEASE" level="project" />
|
||||
<orderEntry type="library" name="Maven: org.springframework.boot:spring-boot-starter-logging:2.2.2.RELEASE" level="project" />
|
||||
<orderEntry type="library" name="Maven: ch.qos.logback:logback-classic:1.2.3" level="project" />
|
||||
<orderEntry type="library" name="Maven: ch.qos.logback:logback-core:1.2.3" level="project" />
|
||||
<orderEntry type="library" name="Maven: org.apache.logging.log4j:log4j-to-slf4j:2.12.1" level="project" />
|
||||
<orderEntry type="library" name="Maven: org.apache.logging.log4j:log4j-api:2.12.1" level="project" />
|
||||
<orderEntry type="library" name="Maven: org.slf4j:jul-to-slf4j:1.7.29" level="project" />
|
||||
<orderEntry type="library" name="Maven: jakarta.annotation:jakarta.annotation-api:1.3.5" level="project" />
|
||||
<orderEntry type="library" name="Maven: org.yaml:snakeyaml:1.25" level="project" />
|
||||
<orderEntry type="library" name="Maven: org.springframework.boot:spring-boot-starter-json:2.2.2.RELEASE" level="project" />
|
||||
<orderEntry type="library" name="Maven: com.fasterxml.jackson.datatype:jackson-datatype-jdk8:2.10.1" level="project" />
|
||||
<orderEntry type="library" name="Maven: com.fasterxml.jackson.datatype:jackson-datatype-jsr310:2.10.1" level="project" />
|
||||
<orderEntry type="library" name="Maven: com.fasterxml.jackson.module:jackson-module-parameter-names:2.10.1" level="project" />
|
||||
<orderEntry type="library" name="Maven: org.springframework.boot:spring-boot-starter-tomcat:2.2.2.RELEASE" level="project" />
|
||||
<orderEntry type="library" name="Maven: org.apache.tomcat.embed:tomcat-embed-core:9.0.29" level="project" />
|
||||
<orderEntry type="library" name="Maven: org.apache.tomcat.embed:tomcat-embed-websocket:9.0.29" level="project" />
|
||||
<orderEntry type="library" name="Maven: org.springframework:spring-web:5.2.2.RELEASE" level="project" />
|
||||
<orderEntry type="library" name="Maven: org.springframework:spring-beans:5.2.2.RELEASE" level="project" />
|
||||
<orderEntry type="library" name="Maven: org.springframework:spring-webmvc:5.2.2.RELEASE" level="project" />
|
||||
<orderEntry type="library" name="Maven: org.springframework:spring-context:5.2.2.RELEASE" level="project" />
|
||||
<orderEntry type="library" name="Maven: org.springframework:spring-expression:5.2.2.RELEASE" level="project" />
|
||||
<orderEntry type="library" name="Maven: org.projectlombok:lombok:1.18.10" level="project" />
|
||||
<orderEntry type="library" scope="TEST" name="Maven: org.springframework.boot:spring-boot-starter-test:2.2.2.RELEASE" level="project" />
|
||||
<orderEntry type="library" scope="TEST" name="Maven: org.springframework.boot:spring-boot-test:2.2.2.RELEASE" level="project" />
|
||||
<orderEntry type="library" scope="TEST" name="Maven: org.springframework.boot:spring-boot-test-autoconfigure:2.2.2.RELEASE" level="project" />
|
||||
<orderEntry type="library" scope="TEST" name="Maven: com.jayway.jsonpath:json-path:2.4.0" level="project" />
|
||||
<orderEntry type="library" scope="TEST" name="Maven: net.minidev:json-smart:2.3" level="project" />
|
||||
<orderEntry type="library" scope="TEST" name="Maven: net.minidev:accessors-smart:1.2" level="project" />
|
||||
<orderEntry type="library" scope="TEST" name="Maven: org.ow2.asm:asm:5.0.4" level="project" />
|
||||
<orderEntry type="library" name="Maven: org.slf4j:slf4j-api:1.7.29" level="project" />
|
||||
<orderEntry type="library" name="Maven: jakarta.xml.bind:jakarta.xml.bind-api:2.3.2" level="project" />
|
||||
<orderEntry type="library" name="Maven: jakarta.activation:jakarta.activation-api:1.2.1" level="project" />
|
||||
<orderEntry type="library" scope="TEST" name="Maven: org.junit.jupiter:junit-jupiter:5.5.2" level="project" />
|
||||
<orderEntry type="library" scope="TEST" name="Maven: org.junit.jupiter:junit-jupiter-api:5.5.2" level="project" />
|
||||
<orderEntry type="library" scope="TEST" name="Maven: org.opentest4j:opentest4j:1.2.0" level="project" />
|
||||
<orderEntry type="library" scope="TEST" name="Maven: org.junit.platform:junit-platform-commons:1.5.2" level="project" />
|
||||
<orderEntry type="library" scope="TEST" name="Maven: org.junit.jupiter:junit-jupiter-params:5.5.2" level="project" />
|
||||
<orderEntry type="library" scope="TEST" name="Maven: org.junit.jupiter:junit-jupiter-engine:5.5.2" level="project" />
|
||||
<orderEntry type="library" scope="TEST" name="Maven: org.junit.vintage:junit-vintage-engine:5.5.2" level="project" />
|
||||
<orderEntry type="library" scope="TEST" name="Maven: org.apiguardian:apiguardian-api:1.1.0" level="project" />
|
||||
<orderEntry type="library" scope="TEST" name="Maven: org.junit.platform:junit-platform-engine:1.5.2" level="project" />
|
||||
<orderEntry type="library" scope="TEST" name="Maven: junit:junit:4.12" level="project" />
|
||||
<orderEntry type="library" scope="TEST" name="Maven: org.mockito:mockito-junit-jupiter:3.1.0" level="project" />
|
||||
<orderEntry type="library" scope="TEST" name="Maven: org.assertj:assertj-core:3.13.2" level="project" />
|
||||
<orderEntry type="library" scope="TEST" name="Maven: org.hamcrest:hamcrest:2.1" level="project" />
|
||||
<orderEntry type="library" scope="TEST" name="Maven: org.mockito:mockito-core:3.1.0" level="project" />
|
||||
<orderEntry type="library" name="Maven: net.bytebuddy:byte-buddy:1.10.4" level="project" />
|
||||
<orderEntry type="library" scope="TEST" name="Maven: net.bytebuddy:byte-buddy-agent:1.10.4" level="project" />
|
||||
<orderEntry type="library" scope="TEST" name="Maven: org.objenesis:objenesis:2.6" level="project" />
|
||||
<orderEntry type="library" scope="TEST" name="Maven: org.skyscreamer:jsonassert:1.5.0" level="project" />
|
||||
<orderEntry type="library" scope="TEST" name="Maven: com.vaadin.external.google:android-json:0.0.20131108.vaadin1" level="project" />
|
||||
<orderEntry type="library" name="Maven: org.springframework:spring-core:5.2.2.RELEASE" level="project" />
|
||||
<orderEntry type="library" name="Maven: org.springframework:spring-jcl:5.2.2.RELEASE" level="project" />
|
||||
<orderEntry type="library" scope="TEST" name="Maven: org.springframework:spring-test:5.2.2.RELEASE" level="project" />
|
||||
<orderEntry type="library" scope="TEST" name="Maven: org.xmlunit:xmlunit-core:2.6.3" level="project" />
|
||||
<orderEntry type="library" name="Maven: org.springframework.boot:spring-boot-starter-data-redis:2.2.2.RELEASE" level="project" />
|
||||
<orderEntry type="library" name="Maven: org.springframework.data:spring-data-redis:2.2.3.RELEASE" level="project" />
|
||||
<orderEntry type="library" name="Maven: org.springframework.data:spring-data-keyvalue:2.2.3.RELEASE" level="project" />
|
||||
<orderEntry type="library" name="Maven: org.springframework.data:spring-data-commons:2.2.3.RELEASE" level="project" />
|
||||
<orderEntry type="library" name="Maven: org.springframework:spring-tx:5.2.2.RELEASE" level="project" />
|
||||
<orderEntry type="library" name="Maven: org.springframework:spring-oxm:5.2.2.RELEASE" level="project" />
|
||||
<orderEntry type="library" name="Maven: org.springframework:spring-context-support:5.2.2.RELEASE" level="project" />
|
||||
<orderEntry type="library" name="Maven: io.lettuce:lettuce-core:5.2.1.RELEASE" level="project" />
|
||||
<orderEntry type="library" name="Maven: io.netty:netty-common:4.1.43.Final" level="project" />
|
||||
<orderEntry type="library" name="Maven: io.netty:netty-handler:4.1.43.Final" level="project" />
|
||||
<orderEntry type="library" name="Maven: io.netty:netty-buffer:4.1.43.Final" level="project" />
|
||||
<orderEntry type="library" name="Maven: io.netty:netty-codec:4.1.43.Final" level="project" />
|
||||
<orderEntry type="library" name="Maven: io.netty:netty-transport:4.1.43.Final" level="project" />
|
||||
<orderEntry type="library" name="Maven: io.netty:netty-resolver:4.1.43.Final" level="project" />
|
||||
<orderEntry type="library" name="Maven: io.projectreactor:reactor-core:3.3.1.RELEASE" level="project" />
|
||||
<orderEntry type="library" name="Maven: org.reactivestreams:reactive-streams:1.0.3" level="project" />
|
||||
<orderEntry type="library" name="Maven: org.springframework.boot:spring-boot-configuration-processor:2.2.2.RELEASE" level="project" />
|
||||
<orderEntry type="library" name="Maven: org.springframework.boot:spring-boot-starter-security:2.2.2.RELEASE" level="project" />
|
||||
<orderEntry type="library" name="Maven: org.springframework:spring-aop:5.2.2.RELEASE" level="project" />
|
||||
<orderEntry type="library" name="Maven: org.springframework.security:spring-security-config:5.2.1.RELEASE" level="project" />
|
||||
<orderEntry type="library" name="Maven: org.springframework.security:spring-security-core:5.2.1.RELEASE" level="project" />
|
||||
<orderEntry type="library" name="Maven: org.springframework.security:spring-security-web:5.2.1.RELEASE" level="project" />
|
||||
<orderEntry type="library" name="Maven: org.springframework.security:spring-security-jwt:1.1.1.RELEASE" level="project" />
|
||||
<orderEntry type="library" name="Maven: org.bouncycastle:bcpkix-jdk15on:1.64" level="project" />
|
||||
<orderEntry type="library" name="Maven: org.bouncycastle:bcprov-jdk15on:1.64" level="project" />
|
||||
<orderEntry type="library" name="Maven: mysql:mysql-connector-java:8.0.18" level="project" />
|
||||
<orderEntry type="library" name="Maven: com.baomidou:mybatis-plus-boot-starter:3.5.2" level="project" />
|
||||
<orderEntry type="library" name="Maven: com.baomidou:mybatis-plus:3.5.2" level="project" />
|
||||
<orderEntry type="library" name="Maven: com.baomidou:mybatis-plus-extension:3.5.2" level="project" />
|
||||
<orderEntry type="library" name="Maven: com.baomidou:mybatis-plus-core:3.5.2" level="project" />
|
||||
<orderEntry type="library" name="Maven: com.baomidou:mybatis-plus-annotation:3.5.2" level="project" />
|
||||
<orderEntry type="library" name="Maven: com.github.jsqlparser:jsqlparser:4.4" level="project" />
|
||||
<orderEntry type="library" name="Maven: org.mybatis:mybatis:3.5.10" level="project" />
|
||||
<orderEntry type="library" name="Maven: org.mybatis:mybatis-spring:2.0.7" level="project" />
|
||||
<orderEntry type="library" name="Maven: org.jetbrains.kotlin:kotlin-stdlib-jdk8:1.3.61" level="project" />
|
||||
<orderEntry type="library" name="Maven: org.jetbrains.kotlin:kotlin-stdlib:1.3.61" level="project" />
|
||||
<orderEntry type="library" name="Maven: org.jetbrains.kotlin:kotlin-stdlib-common:1.3.61" level="project" />
|
||||
<orderEntry type="library" name="Maven: org.jetbrains:annotations:13.0" level="project" />
|
||||
<orderEntry type="library" name="Maven: org.jetbrains.kotlin:kotlin-stdlib-jdk7:1.3.61" level="project" />
|
||||
<orderEntry type="library" name="Maven: org.springframework.boot:spring-boot-autoconfigure:2.2.2.RELEASE" level="project" />
|
||||
<orderEntry type="library" name="Maven: org.springframework.boot:spring-boot-starter-jdbc:2.2.2.RELEASE" level="project" />
|
||||
<orderEntry type="library" name="Maven: com.zaxxer:HikariCP:3.4.1" level="project" />
|
||||
<orderEntry type="library" name="Maven: org.springframework:spring-jdbc:5.2.2.RELEASE" level="project" />
|
||||
<orderEntry type="library" name="Maven: org.springframework.boot:spring-boot-starter-validation:2.2.2.RELEASE" level="project" />
|
||||
<orderEntry type="library" name="Maven: jakarta.validation:jakarta.validation-api:2.0.1" level="project" />
|
||||
<orderEntry type="library" name="Maven: org.apache.tomcat.embed:tomcat-embed-el:9.0.29" level="project" />
|
||||
<orderEntry type="library" name="Maven: org.hibernate.validator:hibernate-validator:6.0.18.Final" level="project" />
|
||||
<orderEntry type="library" name="Maven: org.jboss.logging:jboss-logging:3.4.1.Final" level="project" />
|
||||
<orderEntry type="library" name="Maven: com.fasterxml:classmate:1.5.1" level="project" />
|
||||
<orderEntry type="library" name="Maven: cn.hutool:hutool-all:5.8.2" level="project" />
|
||||
<orderEntry type="library" name="Maven: com.alibaba:fastjson:2.0.6.graal" level="project" />
|
||||
<orderEntry type="library" name="Maven: com.alibaba.fastjson2:fastjson2-extension:2.0.6.graal" level="project" />
|
||||
<orderEntry type="library" name="Maven: com.alibaba.fastjson2:fastjson2:2.0.6.graal" level="project" />
|
||||
<orderEntry type="library" name="Maven: io.jsonwebtoken:jjwt:0.9.1" level="project" />
|
||||
<orderEntry type="library" name="Maven: com.fasterxml.jackson.core:jackson-databind:2.10.1" level="project" />
|
||||
<orderEntry type="library" name="Maven: com.fasterxml.jackson.core:jackson-annotations:2.10.1" level="project" />
|
||||
<orderEntry type="library" name="Maven: com.fasterxml.jackson.core:jackson-core:2.10.1" level="project" />
|
||||
<orderEntry type="library" name="Maven: com.squareup.okhttp3:okhttp:3.14.2" level="project" />
|
||||
<orderEntry type="library" name="Maven: com.squareup.okio:okio:1.17.2" level="project" />
|
||||
<orderEntry type="library" name="Maven: javax.xml.bind:jaxb-api:2.4.0-b180830.0359" level="project" />
|
||||
<orderEntry type="library" name="Maven: javax.activation:javax.activation-api:1.2.0" level="project" />
|
||||
<orderEntry type="library" name="Maven: com.sun.xml.bind:jaxb-impl:4.0.0" level="project" />
|
||||
<orderEntry type="library" name="Maven: com.sun.xml.bind:jaxb-core:4.0.0" level="project" />
|
||||
<orderEntry type="library" scope="RUNTIME" name="Maven: org.eclipse.angus:angus-activation:1.0.0" level="project" />
|
||||
<orderEntry type="library" name="Maven: javax.activation:activation:1.1.1" level="project" />
|
||||
<orderEntry type="library" name="Maven: com.github.whvcse:easy-captcha:1.6.2" level="project" />
|
||||
<orderEntry type="library" name="Maven: com.google.guava:guava:31.1-jre" level="project" />
|
||||
<orderEntry type="library" name="Maven: com.google.guava:failureaccess:1.0.1" level="project" />
|
||||
<orderEntry type="library" name="Maven: com.google.guava:listenablefuture:9999.0-empty-to-avoid-conflict-with-guava" level="project" />
|
||||
<orderEntry type="library" name="Maven: com.google.code.findbugs:jsr305:3.0.2" level="project" />
|
||||
<orderEntry type="library" name="Maven: org.checkerframework:checker-qual:3.12.0" level="project" />
|
||||
<orderEntry type="library" name="Maven: com.google.errorprone:error_prone_annotations:2.11.0" level="project" />
|
||||
<orderEntry type="library" name="Maven: com.google.j2objc:j2objc-annotations:1.3" level="project" />
|
||||
<orderEntry type="library" name="Maven: com.github.xiaoymin:knife4j-spring-boot-starter:3.0.3" level="project" />
|
||||
<orderEntry type="library" name="Maven: com.github.xiaoymin:knife4j-spring-boot-autoconfigure:3.0.3" level="project" />
|
||||
<orderEntry type="library" name="Maven: com.github.xiaoymin:knife4j-spring:3.0.3" level="project" />
|
||||
<orderEntry type="library" name="Maven: com.github.xiaoymin:knife4j-annotations:3.0.3" level="project" />
|
||||
<orderEntry type="library" name="Maven: io.swagger:swagger-annotations:1.5.22" level="project" />
|
||||
<orderEntry type="library" name="Maven: io.swagger.core.v3:swagger-annotations:2.1.2" level="project" />
|
||||
<orderEntry type="library" name="Maven: com.github.xiaoymin:knife4j-core:3.0.3" level="project" />
|
||||
<orderEntry type="library" name="Maven: org.javassist:javassist:3.25.0-GA" level="project" />
|
||||
<orderEntry type="library" name="Maven: io.springfox:springfox-swagger2:3.0.0" level="project" />
|
||||
<orderEntry type="library" name="Maven: io.springfox:springfox-spi:3.0.0" level="project" />
|
||||
<orderEntry type="library" name="Maven: io.springfox:springfox-schema:3.0.0" level="project" />
|
||||
<orderEntry type="library" name="Maven: io.springfox:springfox-swagger-common:3.0.0" level="project" />
|
||||
<orderEntry type="library" name="Maven: io.springfox:springfox-spring-web:3.0.0" level="project" />
|
||||
<orderEntry type="library" name="Maven: io.github.classgraph:classgraph:4.8.83" level="project" />
|
||||
<orderEntry type="library" name="Maven: io.springfox:springfox-spring-webflux:3.0.0" level="project" />
|
||||
<orderEntry type="library" scope="RUNTIME" name="Maven: org.mapstruct:mapstruct:1.3.1.Final" level="project" />
|
||||
<orderEntry type="library" name="Maven: io.springfox:springfox-spring-webmvc:3.0.0" level="project" />
|
||||
<orderEntry type="library" name="Maven: io.springfox:springfox-core:3.0.0" level="project" />
|
||||
<orderEntry type="library" name="Maven: io.springfox:springfox-oas:3.0.0" level="project" />
|
||||
<orderEntry type="library" name="Maven: io.swagger.core.v3:swagger-models:2.1.2" level="project" />
|
||||
<orderEntry type="library" name="Maven: io.springfox:springfox-bean-validators:3.0.0" level="project" />
|
||||
<orderEntry type="library" name="Maven: io.swagger:swagger-models:1.5.22" level="project" />
|
||||
<orderEntry type="library" name="Maven: io.swagger:swagger-core:1.5.22" level="project" />
|
||||
<orderEntry type="library" name="Maven: org.apache.commons:commons-lang3:3.9" level="project" />
|
||||
<orderEntry type="library" name="Maven: com.fasterxml.jackson.dataformat:jackson-dataformat-yaml:2.10.1" level="project" />
|
||||
<orderEntry type="library" name="Maven: javax.validation:validation-api:2.0.1.Final" level="project" />
|
||||
<orderEntry type="library" name="Maven: io.springfox:springfox-boot-starter:3.0.0" level="project" />
|
||||
<orderEntry type="library" name="Maven: io.springfox:springfox-data-rest:3.0.0" level="project" />
|
||||
<orderEntry type="library" name="Maven: org.springframework.plugin:spring-plugin-core:2.0.0.RELEASE" level="project" />
|
||||
<orderEntry type="library" name="Maven: org.springframework.plugin:spring-plugin-metadata:2.0.0.RELEASE" level="project" />
|
||||
<orderEntry type="library" name="Maven: com.github.xiaoymin:knife4j-spring-ui:3.0.3" level="project" />
|
||||
<orderEntry type="library" name="Maven: com.tencentcloudapi:tencentcloud-sdk-java-ses:3.1.572" level="project" />
|
||||
<orderEntry type="library" name="Maven: com.tencentcloudapi:tencentcloud-sdk-java-common:3.1.572" level="project" />
|
||||
<orderEntry type="library" name="Maven: commons-logging:commons-logging:1.2" level="project" />
|
||||
<orderEntry type="library" name="Maven: com.squareup.okhttp:okhttp:2.7.5" level="project" />
|
||||
<orderEntry type="library" name="Maven: com.google.code.gson:gson:2.8.6" level="project" />
|
||||
<orderEntry type="library" name="Maven: com.squareup.okhttp:logging-interceptor:2.7.5" level="project" />
|
||||
<orderEntry type="library" name="Maven: org.ini4j:ini4j:0.5.4" level="project" />
|
||||
</component>
|
||||
</module>
|
||||
9
files/COD-public-key.txt
Normal file
9
files/COD-public-key.txt
Normal file
@@ -0,0 +1,9 @@
|
||||
-----BEGIN PUBLIC KEY-----
|
||||
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAymkBAWixxUi9IAeMWgsq
|
||||
K92AzFbe0qzzYPdkoh15ymL2A5MkYH7asnhFwclgdiFmd9a0TbZP+t/SzWW8UUzN
|
||||
1pXoEp48R+eguGTt5xkJwb10+H6quVXF/Ezzid5yzVW3dcYRp8qUlFr0XBpvkK9l
|
||||
FpPzh2+mwVEAsgBMXq/K50ZiX2dlkPZ7ffkVPWaK2ESIo3YgfM6dmiiza0hPWJ35
|
||||
UgTH5rwJ7vN3IdOJTlkQOvrIrj2ocPcrudeEwqybIbCGhgRBwQSBsXQOO4U//rE4
|
||||
VU+0LF/3uQgXkvVY1+a1JLiTncZYKGEQ/NtxM+dGtYWV2gPhQRyJ7Z77OX0XCbcn
|
||||
zwIDAQAB
|
||||
-----END PUBLIC KEY-----
|
||||
@@ -0,0 +1,28 @@
|
||||
-----BEGIN PRIVATE KEY-----
|
||||
MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQDD+NUduhLJcb2Z
|
||||
ryLwtIHdmjfh6Wn73E9umHmdPf6yF7IbDoTDBmIAfaPU/oiLgrka3fKGCkn/yHvW
|
||||
QcL+Ry96/Uu+iIN9SbG5vPVvLtLfx+5++IE8p3RxcSDQggqFuJ+osebXeVIrOcTZ
|
||||
s7nXCqGenTcagv2eJESiq712fcBvY1wVgilT6ERVQy+zdvwAOiS6wXF/51AueP+E
|
||||
rNDHuPLkGH6JhLtO4LffeYgM/Th7eCl/WWLkiVMSoeJt7vWFe4bYV/IYW1qI2aQX
|
||||
H1DYmvwgDfDv8jRORD9D191YBqq1l3Tw7VSjFrpydFvSK46dbXKBj3oA5ZiJ+Ttj
|
||||
ZCtBRiOdAgMBAAECggEAUKl4Fs9C8lV1o+85Y3f4yBy1CbCIZhltPGlYDUe6MNWe
|
||||
ApL8REW5Sthr+bx2uW2qAQv/yfosMTL0/eB9gSoNugLODXOlI4mUtI25O/U66M8j
|
||||
NHHWx/9o51SYHBqaeCXg2Y+4I1KVZqNVigH26TNACMhPKQNnnpLxCT/FMSNbdLzo
|
||||
wfFMyjN7R3Hc8ZB1C2zx+fLJm1DNZeOJOHAkW1LprlotRv6eq3lOwZaDDUTB5xhT
|
||||
0Erev3djC/R08Fne1y09ukar8z0tX3Fm9SzHJDFVoh1HOYPWayCiAxOhip+JnFct
|
||||
rtK5jjuB8DAP4Q1k12yOWUFwb6NOG9Hf/G6XExRPBQKBgQD1P2SnKD1IlNSrvVJn
|
||||
2HzKnBVllVo50fbv7SpnP8H1B5vt2Qo/mgOGtzbeXyK4mcLFaWg9++BrsjTXwZFi
|
||||
wmKeJgNI822DPhF5qQhK7Cc+WMwesufGrTnmRUOEFYehz9ffZBvMa1s/ObIEyLcr
|
||||
tYitT74+nFdRPtr+8PN06QMEcwKBgQDMkGFWhSO7p7VMuV0H0uC1fj3GGtVvM+Ps
|
||||
a9ASs0HBhQaOpberkKY9vgry6HoJ8CGvbrxlmc3JoYPRwKN3oQRYLvGSF96HAg9i
|
||||
643FmVAWiVzHpjYX9fMJyCzXiOw6Qet8Zp3Ewaw9BBG0200Fj6/zGc8XEqNjIv5Q
|
||||
DQ9MosRDrwKBgQCU5i5IRugeXy5YLxQPNKNfqDBdgrZLEK2qsgXithUencYQPIw6
|
||||
XVnyut43WO+NwN0+WmcN6xUwjfwDWuTYX0jc2Bt6eUFuQ4r8oKIGSybwdZ1IrjqG
|
||||
p7nVkwwQ77lvhu98FB3EmRHHa1IoEW0Uvp0DDL1m6ikhjNYNn2FRA//u/QKBgGbY
|
||||
a+eo1ldBMPha9Te6wLjeuEYCNa5L41p4tcrBDt0xeSN8k4QRHFNMWYrYcIrQjM77
|
||||
mIJoOjsWFgT9mfHKJToEl/VAROORmJS+Iq/mrYo3E0tY+DdBsygG2Oyf7Uw42iDY
|
||||
IpfKW0Lt6c0IuIeEPwy0vBY4i6aK8Frkxf1ck9oHAoGBAKFQg/c36J6tjnttpmes
|
||||
R/zijp1ROE+z+dMmm3icDhCDvvR6MnHa2Y9ittNWdEUosZk9FsFn62YNtJJV2SIN
|
||||
DDn0ASLtBkeCd8yad5uzUb7Umci9V7TP5c0NE3DK95FmciLGOuRbFyq1Z8edHnaS
|
||||
zgLnf4yb25eCMLEG0Z2ugN3C
|
||||
-----END PRIVATE KEY-----
|
||||
9
files/Code-Create Limited.merchant.aqs.public.key.pem
Normal file
9
files/Code-Create Limited.merchant.aqs.public.key.pem
Normal file
@@ -0,0 +1,9 @@
|
||||
-----BEGIN PUBLIC KEY-----
|
||||
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAw/jVHboSyXG9ma8i8LSB
|
||||
3Zo34elp+9xPbph5nT3+sheyGw6EwwZiAH2j1P6Ii4K5Gt3yhgpJ/8h71kHC/kcv
|
||||
ev1LvoiDfUmxubz1by7S38fufviBPKd0cXEg0IIKhbifqLHm13lSKznE2bO51wqh
|
||||
np03GoL9niREoqu9dn3Ab2NcFYIpU+hEVUMvs3b8ADokusFxf+dQLnj/hKzQx7jy
|
||||
5Bh+iYS7TuC333mIDP04e3gpf1li5IlTEqHibe71hXuG2FfyGFtaiNmkFx9Q2Jr8
|
||||
IA3w7/I0TkQ/Q9fdWAaqtZd08O1Uoxa6cnRb0iuOnW1ygY96AOWYifk7Y2QrQUYj
|
||||
nQIDAQAB
|
||||
-----END PUBLIC KEY-----
|
||||
640
pom.xml
640
pom.xml
@@ -1,160 +1,480 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<parent>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-parent</artifactId>
|
||||
<version>2.2.2.RELEASE</version>
|
||||
<relativePath/> <!-- lookup parent from repository -->
|
||||
</parent>
|
||||
<groupId>com.aida</groupId>
|
||||
<artifactId>aida</artifactId>
|
||||
<version>0.0.1-SNAPSHOT</version>
|
||||
<name>aida</name>
|
||||
<description>ai da</description>
|
||||
<properties>
|
||||
<java.version>8</java.version>
|
||||
<mybatis.plus.version>3.5.2</mybatis.plus.version>
|
||||
<hutool.version>5.8.2</hutool.version>
|
||||
<wx.java.version>4.2.7.B</wx.java.version>
|
||||
<fastjson.version>2.0.6.graal</fastjson.version>
|
||||
<security.jwt.version>1.1.1.RELEASE</security.jwt.version>
|
||||
<jjwt.version>0.9.1</jjwt.version>
|
||||
<guava.version>31.1-jre</guava.version>
|
||||
|
||||
<jaxb-api>2.4.0-b180830.0359</jaxb-api>
|
||||
<jaxb-impl>4.0.0</jaxb-impl>
|
||||
<jaxb-core>4.0.0</jaxb-core>
|
||||
<activation>1.1.1</activation>
|
||||
<easy-captcha>1.6.2</easy-captcha>
|
||||
</properties>
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-web</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.projectlombok</groupId>
|
||||
<artifactId>lombok</artifactId>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-test</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-data-redis</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-configuration-processor</artifactId>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-security</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.security</groupId>
|
||||
<artifactId>spring-security-jwt</artifactId>
|
||||
<version>${security.jwt.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>mysql</groupId>
|
||||
<artifactId>mysql-connector-java</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.baomidou</groupId>
|
||||
<artifactId>mybatis-plus-boot-starter</artifactId>
|
||||
<version>${mybatis.plus.version}</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-validation</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>cn.hutool</groupId>
|
||||
<artifactId>hutool-all</artifactId>
|
||||
<version>${hutool.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.alibaba</groupId>
|
||||
<artifactId>fastjson</artifactId>
|
||||
<version>${fastjson.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>io.jsonwebtoken</groupId>
|
||||
<artifactId>jjwt</artifactId>
|
||||
<version>${jjwt.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.squareup.okhttp3</groupId>
|
||||
<artifactId>okhttp</artifactId>
|
||||
<version>3.14.2</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>javax.xml.bind</groupId>
|
||||
<artifactId>jaxb-api</artifactId>
|
||||
<version>${jaxb-api}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.sun.xml.bind</groupId>
|
||||
<artifactId>jaxb-impl</artifactId>
|
||||
<version>${jaxb-impl}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.sun.xml.bind</groupId>
|
||||
<artifactId>jaxb-core</artifactId>
|
||||
<version>${jaxb-core}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>javax.activation</groupId>
|
||||
<artifactId>activation</artifactId>
|
||||
<version>${activation}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.github.whvcse</groupId>
|
||||
<artifactId>easy-captcha</artifactId>
|
||||
<version>${easy-captcha}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.google.guava</groupId>
|
||||
<artifactId>guava</artifactId>
|
||||
<version>${guava.version}</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>com.github.xiaoymin</groupId>
|
||||
<artifactId>knife4j-spring-boot-starter</artifactId>
|
||||
<version>3.0.3</version>
|
||||
</dependency>
|
||||
<!-- /**发送邮件**/-->
|
||||
<dependency>
|
||||
<groupId>com.tencentcloudapi</groupId>
|
||||
<artifactId>tencentcloud-sdk-java-ses</artifactId>
|
||||
<version>3.1.572</version>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
<build>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-maven-plugin</artifactId>
|
||||
<configuration>
|
||||
<excludes>
|
||||
<exclude>
|
||||
<groupId>org.projectlombok</groupId>
|
||||
<artifactId>lombok</artifactId>
|
||||
</exclude>
|
||||
</excludes>
|
||||
</configuration>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
|
||||
</project>
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<parent>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-parent</artifactId>
|
||||
<version>3.1.6</version>
|
||||
<relativePath/> <!-- lookup parent from repository -->
|
||||
</parent>
|
||||
<groupId>com.aida</groupId>
|
||||
<artifactId>aida</artifactId>
|
||||
<version>0.0.1-SNAPSHOT</version>
|
||||
<name>aida</name>
|
||||
<description>ai da</description>
|
||||
<properties>
|
||||
<java.version>21</java.version>
|
||||
<mybatis.plus.version>3.5.5</mybatis.plus.version>
|
||||
<hutool.version>5.8.23</hutool.version>
|
||||
<wx.java.version>4.2.7.B</wx.java.version>
|
||||
<fastjson.version>2.0.43</fastjson.version>
|
||||
<jjwt.version>0.12.3</jjwt.version>
|
||||
<guava.version>32.1.3-jre</guava.version>
|
||||
|
||||
<easy-captcha>1.6.2</easy-captcha>
|
||||
<aws.java.sdk.version>2.20.43</aws.java.sdk.version>
|
||||
|
||||
<javacv.version>1.5.5</javacv.version>
|
||||
<system.windowsx64>windows-x86_64</system.windowsx64>
|
||||
<javacpp.platform.linux-x86_64>linux-x86_64</javacpp.platform.linux-x86_64>
|
||||
</properties>
|
||||
<dependencyManagement>
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>software.amazon.awssdk</groupId>
|
||||
<artifactId>bom</artifactId>
|
||||
<version>${aws.java.sdk.version}</version>
|
||||
<type>pom</type>
|
||||
<scope>import</scope>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
</dependencyManagement>
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-web</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.projectlombok</groupId>
|
||||
<artifactId>lombok</artifactId>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-test</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-data-redis</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-configuration-processor</artifactId>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-security</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.mysql</groupId>
|
||||
<artifactId>mysql-connector-j</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.baomidou</groupId>
|
||||
<artifactId>mybatis-plus-boot-starter</artifactId>
|
||||
<version>${mybatis.plus.version}</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-validation</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-logging</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>cn.hutool</groupId>
|
||||
<artifactId>hutool-all</artifactId>
|
||||
<version>${hutool.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.alibaba</groupId>
|
||||
<artifactId>fastjson</artifactId>
|
||||
<version>${fastjson.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>io.jsonwebtoken</groupId>
|
||||
<artifactId>jjwt-api</artifactId>
|
||||
<version>${jjwt.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>io.jsonwebtoken</groupId>
|
||||
<artifactId>jjwt-impl</artifactId>
|
||||
<version>${jjwt.version}</version>
|
||||
<scope>runtime</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>io.jsonwebtoken</groupId>
|
||||
<artifactId>jjwt-jackson</artifactId>
|
||||
<version>${jjwt.version}</version>
|
||||
<scope>runtime</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.squareup.okhttp3</groupId>
|
||||
<artifactId>okhttp</artifactId>
|
||||
<version>3.14.2</version>
|
||||
</dependency>
|
||||
<!-- JAXB is included in Java 11+ but needs explicit dependency for Java 9-10 -->
|
||||
<!-- For Java 21, these are not needed as JAXB is part of JDK -->
|
||||
<dependency>
|
||||
<groupId>com.github.whvcse</groupId>
|
||||
<artifactId>easy-captcha</artifactId>
|
||||
<version>${easy-captcha}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.google.guava</groupId>
|
||||
<artifactId>guava</artifactId>
|
||||
<version>${guava.version}</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>com.github.xiaoymin</groupId>
|
||||
<artifactId>knife4j-openapi3-jakarta-spring-boot-starter</artifactId>
|
||||
<version>4.4.0</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springdoc</groupId>
|
||||
<artifactId>springdoc-openapi-starter-webmvc-ui</artifactId>
|
||||
<version>2.3.0</version>
|
||||
</dependency>
|
||||
<!-- Swagger 2 annotations for backward compatibility -->
|
||||
<dependency>
|
||||
<groupId>io.swagger</groupId>
|
||||
<artifactId>swagger-annotations</artifactId>
|
||||
<version>1.6.14</version>
|
||||
</dependency>
|
||||
<!-- /**发送邮件**/-->
|
||||
<!-- <dependency>-->
|
||||
<!-- <groupId>com.tencentcloudapi</groupId>-->
|
||||
<!-- <artifactId>tencentcloud-sdk-java-ses</artifactId>-->
|
||||
<!-- <version>3.1.572</version>-->
|
||||
<!-- </dependency>-->
|
||||
|
||||
<dependency>
|
||||
<groupId>com.tencentcloudapi</groupId>
|
||||
<artifactId>tencentcloud-sdk-java-ses</artifactId>
|
||||
<version>3.1.572</version>
|
||||
</dependency>
|
||||
|
||||
<!--minio-->
|
||||
<dependency>
|
||||
<groupId>io.minio</groupId>
|
||||
<artifactId>minio</artifactId>
|
||||
<version>8.0.3</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>commons-fileupload</groupId>
|
||||
<artifactId>commons-fileupload</artifactId>
|
||||
<version>1.4</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>com.microsoft.sqlserver</groupId>
|
||||
<artifactId>mssql-jdbc</artifactId>
|
||||
<version>12.4.2.jre11</version>
|
||||
</dependency>
|
||||
|
||||
<!-- RabbitMQ -->
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-amqp</artifactId>
|
||||
</dependency>
|
||||
|
||||
<!-- redis 连接池 -->
|
||||
<dependency>
|
||||
<groupId>org.apache.commons</groupId>
|
||||
<artifactId>commons-pool2</artifactId>
|
||||
</dependency>
|
||||
|
||||
<!--支付宝 SDK-->
|
||||
<dependency>
|
||||
<groupId>com.alipay.sdk</groupId>
|
||||
<artifactId>alipay-sdk-java</artifactId>
|
||||
<version>4.22.57.ALL</version>
|
||||
</dependency>
|
||||
|
||||
<!--PayPal SDK-->
|
||||
<dependency>
|
||||
<groupId>com.paypal.sdk</groupId>
|
||||
<artifactId>checkout-sdk</artifactId>
|
||||
<version>1.0.5</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>com.paypal.sdk</groupId>
|
||||
<artifactId>rest-api-sdk</artifactId>
|
||||
<version>LATEST</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.json</groupId>
|
||||
<artifactId>json</artifactId>
|
||||
<version>20230618</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.apache.poi</groupId>
|
||||
<artifactId>poi</artifactId>
|
||||
<version>5.2.4</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.apache.poi</groupId>
|
||||
<artifactId>poi-ooxml</artifactId>
|
||||
<version>5.2.4</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>commons-io</groupId>
|
||||
<artifactId>commons-io</artifactId>
|
||||
<version>2.15.1</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>com.stripe</groupId>
|
||||
<artifactId>stripe-java</artifactId>
|
||||
<version>26.2.0</version>
|
||||
</dependency>
|
||||
|
||||
<!-- aws s3 -->
|
||||
<!-- S3 dependency -->
|
||||
<dependency>
|
||||
<groupId>software.amazon.awssdk</groupId>
|
||||
<artifactId>s3</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>software.amazon.awssdk</groupId>
|
||||
<artifactId>s3-transfer-manager</artifactId>
|
||||
<version>2.17.103-PREVIEW</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>software.amazon.awssdk</groupId>
|
||||
<artifactId>kms</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>software.amazon.awssdk</groupId>
|
||||
<artifactId>s3control</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>com.google.code.gson</groupId>
|
||||
<artifactId>gson</artifactId>
|
||||
<version>2.10.1</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>com.itextpdf</groupId>
|
||||
<artifactId>itextpdf</artifactId>
|
||||
<version>5.5.13.2</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-websocket</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>com.google.auth</groupId>
|
||||
<artifactId>google-auth-library-oauth2-http</artifactId>
|
||||
<version>1.8.0</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>com.google.api-client</groupId>
|
||||
<artifactId>google-api-client</artifactId>
|
||||
<version>1.32.1</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.google.oauth-client</groupId>
|
||||
<artifactId>google-oauth-client</artifactId>
|
||||
<version>1.32.1</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.google.http-client</groupId>
|
||||
<artifactId>google-http-client-jackson2</artifactId>
|
||||
<version>1.41.5</version>
|
||||
</dependency>
|
||||
|
||||
<!-- 邮件发送 -->
|
||||
<!-- thymeleaf -->
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-thymeleaf</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-mail</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>com.alibaba</groupId>
|
||||
<artifactId>easyexcel</artifactId>
|
||||
<version>3.3.3</version>
|
||||
</dependency>
|
||||
<!-- JSON 转义恢复 -->
|
||||
<dependency>
|
||||
<groupId>org.apache.commons</groupId>
|
||||
<artifactId>commons-text</artifactId>
|
||||
<version>1.10.0</version> <!-- 使用最新版本 -->
|
||||
</dependency>
|
||||
|
||||
<!-- 最新版本号:https://mvnrepository.com/artifact/com.alibaba/dashscope-sdk-java -->
|
||||
<!-- 万象SDK -->
|
||||
<dependency>
|
||||
<groupId>com.alibaba</groupId>
|
||||
<artifactId>dashscope-sdk-java</artifactId>
|
||||
<version>2.20.1</version>
|
||||
</dependency>
|
||||
|
||||
<!-- FFmpeg封装(JavaCV) 视频转gif 全部依赖-->
|
||||
<!--<dependency>
|
||||
<groupId>org.bytedeco</groupId>
|
||||
<artifactId>javacv-platform</artifactId>
|
||||
<version>1.5.9</version>
|
||||
</dependency>-->
|
||||
|
||||
<!-- javacv+javacpp核心库-->
|
||||
<dependency>
|
||||
<groupId>org.bytedeco</groupId>
|
||||
<artifactId>javacv</artifactId>
|
||||
<version>${javacv.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.bytedeco</groupId>
|
||||
<artifactId>javacpp-platform</artifactId>
|
||||
<version>${javacv.version}</version>
|
||||
</dependency>
|
||||
<!-- 最小opencv依赖包 ,必须包含上面的javacv+javacpp -->
|
||||
<dependency>
|
||||
<groupId>org.bytedeco</groupId>
|
||||
<artifactId>opencv</artifactId>
|
||||
<version>4.5.1-${javacv.version}</version>
|
||||
<!--<classifier>${system.windowsx64}</classifier>-->
|
||||
<classifier>${javacpp.platform.linux-x86_64}</classifier>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.bytedeco</groupId>
|
||||
<artifactId>openblas</artifactId>
|
||||
<version>0.3.13-${javacv.version}</version>
|
||||
<!--<classifier>${system.windowsx64}</classifier>-->
|
||||
<classifier>${javacpp.platform.linux-x86_64}</classifier>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.bytedeco</groupId>
|
||||
<artifactId>flycapture</artifactId>
|
||||
<version>2.13.3.31-${javacv.version}</version>
|
||||
<!--<classifier>${system.windowsx64}</classifier>-->
|
||||
<classifier>${javacpp.platform.linux-x86_64}</classifier>
|
||||
</dependency>
|
||||
<!-- FFmpeg(视频处理,解决你的报错) -->
|
||||
<dependency>
|
||||
<groupId>org.bytedeco</groupId>
|
||||
<artifactId>ffmpeg</artifactId>
|
||||
<version>4.4-1.5.6</version>
|
||||
<!--<classifier>${system.windowsx64}</classifier>-->
|
||||
<classifier>${javacpp.platform.linux-x86_64}</classifier>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>com.volcengine</groupId>
|
||||
<artifactId>volcengine-java-sdk-ark-runtime</artifactId>
|
||||
<version>0.2.43</version>
|
||||
</dependency>
|
||||
|
||||
<!-- Google 认证库 -->
|
||||
<dependency>
|
||||
<groupId>com.google.auth</groupId>
|
||||
<artifactId>google-auth-library-oauth2-http</artifactId>
|
||||
<version>1.38.0</version>
|
||||
</dependency>
|
||||
|
||||
|
||||
<!-- GIFEncoder 视频转gif-->
|
||||
<dependency>
|
||||
<groupId>com.madgag</groupId>
|
||||
<artifactId>animated-gif-lib</artifactId>
|
||||
<version>1.4</version>
|
||||
</dependency>
|
||||
|
||||
<!-- Jakarta WebSocket API -->
|
||||
<dependency>
|
||||
<groupId>jakarta.websocket</groupId>
|
||||
<artifactId>jakarta.websocket-api</artifactId>
|
||||
<version>2.1.1</version>
|
||||
</dependency>
|
||||
|
||||
<!-- Spring MockMultipartFile 等测试工具,生产代码中也有引用 -->
|
||||
<dependency>
|
||||
<groupId>org.springframework</groupId>
|
||||
<artifactId>spring-test</artifactId>
|
||||
</dependency>
|
||||
|
||||
<!-- BouncyCastle 加密库 -->
|
||||
<dependency>
|
||||
<groupId>org.bouncycastle</groupId>
|
||||
<artifactId>bcprov-jdk18on</artifactId>
|
||||
<version>1.78.1</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.bouncycastle</groupId>
|
||||
<artifactId>bcpkix-jdk18on</artifactId>
|
||||
<version>1.78.1</version>
|
||||
</dependency>
|
||||
<!-- AOP -->
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-aop</artifactId>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
<build>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-maven-plugin</artifactId>
|
||||
<configuration>
|
||||
<excludes>
|
||||
<exclude>
|
||||
<groupId>org.projectlombok</groupId>
|
||||
<artifactId>lombok</artifactId>
|
||||
</exclude>
|
||||
</excludes>
|
||||
</configuration>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
|
||||
<profiles>
|
||||
<profile>
|
||||
<!-- 本地开发环境 -->
|
||||
<id>dev</id>
|
||||
<properties>
|
||||
<profiles.active>dev</profiles.active>
|
||||
</properties>
|
||||
<activation>
|
||||
<activeByDefault>true</activeByDefault>
|
||||
</activation>
|
||||
</profile>
|
||||
<profile>
|
||||
<!-- 测试环境 -->
|
||||
<id>test</id>
|
||||
<properties>
|
||||
<profiles.active>test</profiles.active>
|
||||
</properties>
|
||||
</profile>
|
||||
<profile>
|
||||
<!-- 生产环境 -->
|
||||
<id>prod</id>
|
||||
<properties>
|
||||
<profiles.active>prod</profiles.active>
|
||||
</properties>
|
||||
</profile>
|
||||
</profiles>
|
||||
</project>
|
||||
|
||||
@@ -3,9 +3,13 @@ package com.ai.da;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.boot.SpringApplication;
|
||||
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
||||
import org.springframework.scheduling.annotation.EnableAsync;
|
||||
import org.springframework.scheduling.annotation.EnableScheduling;
|
||||
|
||||
@Slf4j
|
||||
@SpringBootApplication
|
||||
@EnableScheduling
|
||||
@EnableAsync
|
||||
public class AiDaApplication {
|
||||
|
||||
public static void main(String[] args) {
|
||||
|
||||
@@ -0,0 +1,95 @@
|
||||
package com.ai.da.common.RabbitMQ;
|
||||
|
||||
|
||||
import com.ai.da.common.utils.MailUtil;
|
||||
import com.ai.da.model.dto.BasicEmailParamDTO;
|
||||
import com.ai.da.service.EmailService;
|
||||
import com.alibaba.fastjson.JSONObject;
|
||||
import com.rabbitmq.client.Channel;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.amqp.rabbit.annotation.RabbitListener;
|
||||
import org.springframework.core.io.InputStreamSource;
|
||||
import org.springframework.stereotype.Component;
|
||||
import software.amazon.awssdk.core.exception.RetryableException;
|
||||
import org.springframework.amqp.core.Message;
|
||||
|
||||
import jakarta.annotation.Resource;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
|
||||
@Slf4j
|
||||
@Component
|
||||
public class EmailRetryConsumer {
|
||||
|
||||
@Resource
|
||||
private MailUtil mailUtil;
|
||||
@Resource
|
||||
private MQPublisher mqPublisher;
|
||||
@Resource
|
||||
private EmailService emailService;
|
||||
|
||||
// @RabbitListener(queues = "#{rabbitMQProperties.deadLetter.queue}")
|
||||
public void handleRetry(Map<String, String> mailParams, Message message, Channel channel) throws IOException {
|
||||
long tag = message.getMessageProperties().getDeliveryTag();
|
||||
try {
|
||||
log.info("死信队列收到消息:{}", message);
|
||||
// 处理邮件发送参数
|
||||
BasicEmailParamDTO basicEmailParamDTO = JSONObject.parseObject(mailParams.get("dto"), BasicEmailParamDTO.class);
|
||||
String fileName = mailParams.get("filename");
|
||||
InputStreamSource inputStreamSource = Objects.isNull(mailParams.get("source")) ?
|
||||
null : JSONObject.parseObject(mailParams.get("source"), InputStreamSource.class);
|
||||
JSONObject templateParams = JSONObject.parseObject(mailParams.get("templateParams"), JSONObject.class);
|
||||
String templateName = mailParams.get("templatePath");
|
||||
long logId = Long.parseLong(mailParams.get("logId"));
|
||||
basicEmailParamDTO.setContent(mailUtil.setContent(templateParams, templateName));
|
||||
// 发邮件
|
||||
int lastReturnCode = mailUtil.sendMail(basicEmailParamDTO, fileName, inputStreamSource);
|
||||
if (lastReturnCode == 250) {
|
||||
log.info("邮件发送成功!Subject : {}", basicEmailParamDTO.getSubject());
|
||||
emailService.updateStatus(logId, EmailService.DELIVERED);
|
||||
} else if (lastReturnCode == 450) {
|
||||
log.info("目标邮箱 {} 暂时不可用,请稍后重试", (Object) basicEmailParamDTO.getMailTo());
|
||||
// 重试
|
||||
retry(mailParams, message, channel, tag, logId);
|
||||
} else if (lastReturnCode == 550) {
|
||||
log.info("目标邮箱 {} 不可用,邮件发送失败", (Object) basicEmailParamDTO.getMailTo());
|
||||
emailService.updateStatus(logId, EmailService.FAILED);
|
||||
} else {
|
||||
log.info("邮件发送失败,Subject : {}, 状态码: {}", basicEmailParamDTO.getSubject(), lastReturnCode);
|
||||
retry(mailParams, message, channel, tag, logId);
|
||||
emailService.updateStatus(logId, EmailService.FAILED);
|
||||
}
|
||||
channel.basicAck(tag, false);
|
||||
} catch (RetryableException e) {
|
||||
log.info("邮件重试发生异常:RetryableException -> {}", e.getMessage());
|
||||
channel.basicAck(tag, false); // 确认原消息
|
||||
} catch (Exception e) {
|
||||
log.info("邮件重试发生异常:Exception -> {}", e.getMessage());
|
||||
channel.basicAck(tag, false); // 确认原消息
|
||||
}
|
||||
}
|
||||
|
||||
private int getRetryAttempt(Message message) {
|
||||
Integer attempt = message.getMessageProperties()
|
||||
.getHeader("x-retry-attempt");
|
||||
return attempt != null ? attempt : 1;
|
||||
}
|
||||
|
||||
private void retry(Map<String, String> mailParams, Message message, Channel channel, long tag, long logId) throws IOException{
|
||||
int attempt = getRetryAttempt(message);
|
||||
if (attempt >= 3) { // 最大重试次数
|
||||
channel.basicReject(tag, false);
|
||||
emailService.updateStatus(logId, EmailService.FAILED);
|
||||
log.error("重试结束,邮件最终发送失败: {}", mailParams);
|
||||
} else {
|
||||
log.info("重新将邮件信息发送到重试队列");
|
||||
mqPublisher.sendEmailMsg(mailParams, attempt);
|
||||
channel.basicAck(tag, false); // 确认原消息
|
||||
// 更新数据库
|
||||
emailService.updateRetryCount(logId, attempt + 1);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
661
src/main/java/com/ai/da/common/RabbitMQ/GenerateConsumer.java
Normal file
661
src/main/java/com/ai/da/common/RabbitMQ/GenerateConsumer.java
Normal file
@@ -0,0 +1,661 @@
|
||||
package com.ai.da.common.RabbitMQ;
|
||||
|
||||
import com.ai.da.common.config.exception.BusinessException;
|
||||
import com.ai.da.common.constant.CommonConstant;
|
||||
import com.ai.da.common.utils.RedisUtil;
|
||||
import com.ai.da.model.dto.GenerateThroughImageTextDTO;
|
||||
import com.ai.da.model.vo.GenerateResultVO;
|
||||
import com.ai.da.model.vo.PoseTransformationVO;
|
||||
import com.ai.da.service.*;
|
||||
import com.alibaba.fastjson.JSONArray;
|
||||
import com.alibaba.fastjson.JSONObject;
|
||||
import com.fasterxml.jackson.core.JsonParseException;
|
||||
import com.fasterxml.jackson.core.type.TypeReference;
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import com.google.gson.Gson;
|
||||
import com.rabbitmq.client.Channel;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.apache.commons.text.StringEscapeUtils;
|
||||
import org.springframework.amqp.core.Message;
|
||||
import org.springframework.amqp.rabbit.annotation.RabbitHandler;
|
||||
import org.springframework.amqp.rabbit.annotation.RabbitListener;
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.stereotype.Component;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
|
||||
|
||||
@Slf4j
|
||||
@Component
|
||||
@RequiredArgsConstructor
|
||||
public class GenerateConsumer {
|
||||
|
||||
private final GenerateService generateService;
|
||||
|
||||
private final UserLikeGroupService userLikeGroupService;
|
||||
|
||||
private final DesignService designService;
|
||||
|
||||
private final CloudTaskService cloudTaskService;
|
||||
|
||||
private final RabbitMQProperties rabbitMQProperties;
|
||||
|
||||
private final RedisUtil redisUtil;
|
||||
|
||||
private final MessageCenterService messageCenterService;
|
||||
|
||||
@Value("${redis.key.orderForGenerate}")
|
||||
private String consumptionOrderKey;
|
||||
|
||||
@Value("${redis.key.generateCancelSet}")
|
||||
private String cancelSetKey;
|
||||
|
||||
@Value("${redis.key.generateExceptionMap}")
|
||||
private String exceptionMapKey;
|
||||
|
||||
@Value("${redis.key.generateResult}")
|
||||
private String generateResultKey;
|
||||
@Value("${redis.key.toProductImageResultKey}")
|
||||
private String toProductImageResultKey;
|
||||
@Value("${redis.key.relightResultKey}")
|
||||
private String relightResultKey;
|
||||
|
||||
public void generate(Message msg, Channel channel, String consumerName) {
|
||||
log.info("============start listening==========");
|
||||
long start = System.currentTimeMillis();
|
||||
Map<String, String> resp = jsonBytesToMap(msg, channel);
|
||||
String uniqueId = resp.get("tasks_id");
|
||||
// String uniqueId = generateThroughImageTextDTO.getUniqueId();
|
||||
log.info("From " + consumerName + " : " + uniqueId);
|
||||
|
||||
try {
|
||||
// 2、判断当前消息是否在取消列表中
|
||||
Boolean isMember = redisUtil.isElementExistsInSet(cancelSetKey, uniqueId);
|
||||
if (isMember) {
|
||||
try {
|
||||
// 2.1 手动确认该消息
|
||||
channel.basicAck(msg.getMessageProperties().getDeliveryTag(), false);
|
||||
} catch (IOException ex) {
|
||||
log.error("手动确认,不返回队列重新消费");
|
||||
}
|
||||
} else {
|
||||
GenerateThroughImageTextDTO generateThroughImageTextDTO = JSONObject.parseObject(msg.getBody(), GenerateThroughImageTextDTO.class);
|
||||
generateService.generateThroughImageText(generateThroughImageTextDTO);
|
||||
// 将消息从redis排队队列中删除,需保证被消费的消息存储到db之后再从redis删除
|
||||
redisUtil.removeFromZSet(consumptionOrderKey, uniqueId);
|
||||
|
||||
}
|
||||
} catch (Exception e) {
|
||||
log.error(e.getMessage());
|
||||
// channel.basicNack() 为不确认deliveryTag对应的消息,第二个参数是否应用于多消息,第三个参数是否requeue
|
||||
try {
|
||||
// 第二个参数,是否批量确认消息,当传false时,只确认当前 deliveryTag对应的消息;当传true时,会确认当前及之前所有未确认的消息。
|
||||
channel.basicAck(msg.getMessageProperties().getDeliveryTag(), false);
|
||||
// 将消息从redis排队队列中删除,需保证被消费的消息存储到db之后再从redis删除
|
||||
redisUtil.removeFromZSet(consumptionOrderKey, uniqueId);
|
||||
String key = generateResultKey + ":" + uniqueId;
|
||||
GenerateResultVO generateResultVO = new GenerateResultVO(uniqueId, null, null, "Fail");
|
||||
redisUtil.addToString(key, new Gson().toJson(generateResultVO), CommonConstant.GENERATE_RESULT_EXPIRE_TIME);
|
||||
} catch (IOException exception) {
|
||||
log.error("手动确认,取消返回队列,不再重新消费");
|
||||
}
|
||||
// 将入参和错误信息存入数据库
|
||||
String exceptionMessage = JSONObject.toJSONString(resp) +
|
||||
" Exception message : " + e.getMessage();
|
||||
HashMap<String, String> exceptionInfo = new HashMap<>();
|
||||
exceptionInfo.put(String.valueOf(uniqueId), exceptionMessage);
|
||||
// 存redis
|
||||
redisUtil.addToMap(exceptionMapKey, exceptionInfo);
|
||||
}
|
||||
long end = System.currentTimeMillis();
|
||||
|
||||
log.info(" task_id: " + uniqueId + "----------" + consumerName + " 执行时长:" + (end - start) + "毫秒");
|
||||
log.info("=============end listening===========");
|
||||
}
|
||||
|
||||
public void processGenerateResult(Message msg, Channel channel) {
|
||||
log.info("============ProcessGenerateResult listening==========");
|
||||
long start = System.currentTimeMillis();
|
||||
|
||||
Map<String, String> generateResult = jsonBytesToMap(msg, channel);
|
||||
log.info("generate response : {}", generateResult);
|
||||
|
||||
try {
|
||||
log.info("tasks_id : {} start ", generateResult.get("tasks_id"));
|
||||
if (generateResult.get("status").equals("SUCCESS")) {
|
||||
String url = generateResult.get("image_url");
|
||||
String taskId = generateResult.get("tasks_id");
|
||||
String category = generateResult.get("category");
|
||||
generateService.processGenerateResult(taskId, url, category);
|
||||
} else {
|
||||
// 修改redis中的数据状态为exception
|
||||
String key = generateResultKey + ":" + generateResult.get("tasks_id");
|
||||
redisUtil.addToString(key, new Gson().toJson(new GenerateResultVO(generateResult.get("tasks_id"), null, null, "Fail")), CommonConstant.GENERATE_RESULT_EXPIRE_TIME);
|
||||
// 将异常信息存到exception中
|
||||
HashMap<String, String> exceptionInfo = new HashMap<>();
|
||||
exceptionInfo.put(generateResult.get("tasks_id"), generateResult.get("data"));
|
||||
// 存redis
|
||||
redisUtil.addToMap(exceptionMapKey, exceptionInfo);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
log.error(e.getMessage());
|
||||
try {
|
||||
channel.basicAck(msg.getMessageProperties().getDeliveryTag(), false);
|
||||
// 将消息从redis排队队列中删除,需保证被消费的消息存储到db之后再从redis删除
|
||||
redisUtil.removeFromZSet(consumptionOrderKey, generateResult.get("tasks_id"));
|
||||
} catch (IOException exception) {
|
||||
log.error("手动确认,取消返回队列,不再重新消费");
|
||||
}
|
||||
// 将入参和错误信息存入数据库
|
||||
String exceptionMessage = JSONObject.toJSONString(generateResult) +
|
||||
" Exception message : " + e.getMessage();
|
||||
HashMap<String, String> exceptionInfo = new HashMap<>();
|
||||
exceptionInfo.put(String.valueOf(generateResult.get("tasks_id")), exceptionMessage);
|
||||
// 存redis
|
||||
redisUtil.addToMap(exceptionMapKey, exceptionInfo);
|
||||
}
|
||||
|
||||
long end = System.currentTimeMillis();
|
||||
log.info("tasks_id : {}, end , message : {}, 执行时长: {} 毫秒", generateResult.get("tasks_id"), generateResult.get("message"), (end - start));
|
||||
log.info("============ProcessGenerateResult End listening==========");
|
||||
|
||||
}
|
||||
|
||||
public void processToProductImageResult(Message msg, Channel channel) {
|
||||
log.info("============processToProductImageResult listening==========");
|
||||
long start = System.currentTimeMillis();
|
||||
|
||||
Map<String, String> generateResult = jsonBytesToMap(msg, channel);
|
||||
log.info("toProductImage response : {}", generateResult);
|
||||
|
||||
try {
|
||||
log.info("tasks_id : {} start ", generateResult.get("tasks_id"));
|
||||
if (generateResult.get("status").equals("SUCCESS")) {
|
||||
String url = generateResult.get("image_url");
|
||||
String taskId = generateResult.get("tasks_id");
|
||||
String category = generateResult.get("category");
|
||||
generateService.processToProductImageResult(taskId, url, category);
|
||||
} else if (generateResult.get("status").equals("NO_FACE")) {
|
||||
String taskId = generateResult.get("tasks_id");
|
||||
userLikeGroupService.toProduct(taskId);
|
||||
} else {
|
||||
// 修改redis中的数据状态为exception
|
||||
String key = toProductImageResultKey + ":" + generateResult.get("tasks_id");
|
||||
generateService.updateToProductTaskStatus(generateResult.get("tasks_id"), "Fail");
|
||||
redisUtil.addToString(key, new Gson().toJson(new GenerateResultVO(generateResult.get("tasks_id"), null, null, "Fail")), CommonConstant.GENERATE_RESULT_EXPIRE_TIME);
|
||||
// 将异常信息存到exception中
|
||||
HashMap<String, String> exceptionInfo = new HashMap<>();
|
||||
exceptionInfo.put(generateResult.get("tasks_id"), generateResult.get("data"));
|
||||
// 存redis
|
||||
redisUtil.addToMap(exceptionMapKey, exceptionInfo);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
log.error(e.getMessage());
|
||||
try {
|
||||
channel.basicAck(msg.getMessageProperties().getDeliveryTag(), false);
|
||||
// 将消息从redis排队队列中删除,需保证被消费的消息存储到db之后再从redis删除
|
||||
redisUtil.removeFromZSet(consumptionOrderKey, generateResult.get("tasks_id"));
|
||||
} catch (IOException exception) {
|
||||
log.error("手动确认,取消返回队列,不再重新消费");
|
||||
}
|
||||
// 将入参和错误信息存入数据库
|
||||
String exceptionMessage = JSONObject.toJSONString(generateResult) +
|
||||
" Exception message : " + e.getMessage();
|
||||
HashMap<String, String> exceptionInfo = new HashMap<>();
|
||||
exceptionInfo.put(String.valueOf(generateResult.get("tasks_id")), exceptionMessage);
|
||||
// 存redis
|
||||
redisUtil.addToMap(exceptionMapKey, exceptionInfo);
|
||||
}
|
||||
|
||||
long end = System.currentTimeMillis();
|
||||
log.info("tasks_id : {}, end , message : {}, 执行时长: {} 毫秒", generateResult.get("tasks_id"), generateResult.get("message"), (end - start));
|
||||
log.info("============ProcessToProductImageResult End listening==========");
|
||||
}
|
||||
|
||||
private void processRelightResult(Message msg, Channel channel) {
|
||||
log.info("============processRelightResult listening==========");
|
||||
long start = System.currentTimeMillis();
|
||||
|
||||
Map<String, String> generateResult = jsonBytesToMap(msg, channel);
|
||||
log.info("toProductImage response : {}", generateResult);
|
||||
|
||||
try {
|
||||
log.info("tasks_id : {} start ", generateResult.get("tasks_id"));
|
||||
if (generateResult.get("status").equals("SUCCESS")) {
|
||||
String url = generateResult.get("image_url");
|
||||
String taskId = generateResult.get("tasks_id");
|
||||
String category = generateResult.get("category");
|
||||
generateService.processRelightResult(taskId, url, category);
|
||||
} else if (generateResult.get("status").equals("NO_FACE")) {
|
||||
String taskId = generateResult.get("tasks_id");
|
||||
userLikeGroupService.relight(taskId);
|
||||
} else {
|
||||
// 修改redis中的数据状态为exception
|
||||
String key = relightResultKey + ":" + generateResult.get("tasks_id");
|
||||
generateService.updateToProductTaskStatus(generateResult.get("tasks_id"), "Fail");
|
||||
redisUtil.addToString(key, new Gson().toJson(new GenerateResultVO(generateResult.get("tasks_id"), null, null, "Fail")), CommonConstant.GENERATE_RESULT_EXPIRE_TIME);
|
||||
// 将异常信息存到exception中
|
||||
HashMap<String, String> exceptionInfo = new HashMap<>();
|
||||
exceptionInfo.put(generateResult.get("tasks_id"), generateResult.get("data"));
|
||||
// 存redis
|
||||
redisUtil.addToMap(exceptionMapKey, exceptionInfo);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
log.error(e.getMessage());
|
||||
try {
|
||||
channel.basicAck(msg.getMessageProperties().getDeliveryTag(), false);
|
||||
// 将消息从redis排队队列中删除,需保证被消费的消息存储到db之后再从redis删除
|
||||
redisUtil.removeFromZSet(consumptionOrderKey, generateResult.get("tasks_id"));
|
||||
} catch (IOException exception) {
|
||||
log.error("手动确认,取消返回队列,不再重新消费");
|
||||
}
|
||||
// 将入参和错误信息存入数据库
|
||||
String exceptionMessage = JSONObject.toJSONString(generateResult) +
|
||||
" Exception message : " + e.getMessage();
|
||||
HashMap<String, String> exceptionInfo = new HashMap<>();
|
||||
exceptionInfo.put(String.valueOf(generateResult.get("tasks_id")), exceptionMessage);
|
||||
// 存redis
|
||||
redisUtil.addToMap(exceptionMapKey, exceptionInfo);
|
||||
}
|
||||
|
||||
long end = System.currentTimeMillis();
|
||||
log.info("tasks_id : {}, end , message : {}, 执行时长: {} 毫秒", generateResult.get("tasks_id"), generateResult.get("message"), (end - start));
|
||||
log.info("============ProcessRelightResult End listening==========");
|
||||
}
|
||||
|
||||
public void processPoseTransformResult(Message msg, Channel channel) {
|
||||
log.info("============ProcessPoseTransformResult listening==========");
|
||||
long start = System.currentTimeMillis();
|
||||
|
||||
Map<String, String> generateResult = jsonBytesToMap(msg, channel);
|
||||
log.info("PoseTransformation response : {}", generateResult);
|
||||
|
||||
try {
|
||||
log.info("tasks_id : {} start ", generateResult.get("tasks_id"));
|
||||
if (generateResult.get("status").equals("SUCCESS")) {
|
||||
String gifUrl = generateResult.get("gif_url");
|
||||
String taskId = generateResult.get("tasks_id");
|
||||
String videoUrl = generateResult.get("video_url");
|
||||
String imageUrl = generateResult.get("image_url");
|
||||
generateService.processPoseTransformResult(taskId, gifUrl, videoUrl, imageUrl);
|
||||
} else {
|
||||
// 修改redis中的数据状态为exception
|
||||
String key = generateResultKey + ":" + generateResult.get("tasks_id");
|
||||
generateService.updatePoseTransferStatus(generateResult.get("tasks_id"), "Fail", null);
|
||||
redisUtil.addToString(key, new Gson().toJson(new PoseTransformationVO(null, generateResult.get("tasks_id"),null, null, null, (byte)0, "Fail")), CommonConstant.GENERATE_RESULT_EXPIRE_TIME);
|
||||
// 将异常信息存到exception中
|
||||
HashMap<String, String> exceptionInfo = new HashMap<>();
|
||||
exceptionInfo.put(generateResult.get("tasks_id"), generateResult.get("message"));
|
||||
// 存redis
|
||||
redisUtil.addToMap(exceptionMapKey, exceptionInfo);
|
||||
// 记录失败状态并向用户发送提示消息
|
||||
generateService.processPTFailSituation(generateResult.get("tasks_id"));
|
||||
}
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
log.error(e.getMessage());
|
||||
try {
|
||||
channel.basicAck(msg.getMessageProperties().getDeliveryTag(), false);
|
||||
// 将消息从redis排队队列中删除,需保证被消费的消息存储到db之后再从redis删除
|
||||
redisUtil.removeFromZSet(consumptionOrderKey, generateResult.get("tasks_id"));
|
||||
} catch (IOException exception) {
|
||||
log.error("手动确认,取消返回队列,不再重新消费");
|
||||
}
|
||||
// 将入参和错误信息存入数据库
|
||||
String exceptionMessage = JSONObject.toJSONString(generateResult) +
|
||||
" Exception message : " + e.getMessage();
|
||||
HashMap<String, String> exceptionInfo = new HashMap<>();
|
||||
exceptionInfo.put(String.valueOf(generateResult.get("tasks_id")), exceptionMessage);
|
||||
// 存redis
|
||||
redisUtil.addToMap(exceptionMapKey, exceptionInfo);
|
||||
// 记录失败状态并向用户发送提示消息
|
||||
generateService.processPTFailSituation(generateResult.get("tasks_id"));
|
||||
}
|
||||
|
||||
long end = System.currentTimeMillis();
|
||||
log.info("tasks_id : {}, end , message : {}, 执行时长: {} 毫秒", generateResult.get("tasks_id"), generateResult.get("message"), (end - start));
|
||||
log.info("============ProcessPoseTransformResult End listening==========");
|
||||
|
||||
}
|
||||
|
||||
public static Map<String, String> jsonBytesToMap(Message msg, Channel channel) {
|
||||
try {
|
||||
// 1. byte[] -> String
|
||||
String jsonString = new String(msg.getBody(), StandardCharsets.UTF_8).trim();
|
||||
// 2. 处理可能的双重转义
|
||||
if (jsonString.startsWith("\"") && jsonString.endsWith("\"")) {
|
||||
jsonString = jsonString.substring(1, jsonString.length() - 1);
|
||||
// 使用 Apache Commons Text, 将 JSON 字符串中的转义字符还原为原始字符
|
||||
jsonString = StringEscapeUtils.unescapeJson(jsonString);
|
||||
}
|
||||
// 3. 验证 JSON 格式
|
||||
if (!isValidJson(jsonString)) {
|
||||
throw new IllegalArgumentException("Invalid JSON format");
|
||||
}
|
||||
// 4. 解析为 Map
|
||||
ObjectMapper mapper = new ObjectMapper();
|
||||
return mapper.readValue(jsonString, new TypeReference<Map<String, String>>() {});
|
||||
} catch (Exception e) {
|
||||
log.error("消息解析失败: {}", e.getMessage(), e);
|
||||
try {
|
||||
// 仅对不可恢复错误(如非 JSON 数据)进行 ACK
|
||||
if (e instanceof JsonParseException || e instanceof IllegalArgumentException) {
|
||||
channel.basicAck(msg.getMessageProperties().getDeliveryTag(), false);
|
||||
log.warn("因消息格式错误,已确认并丢弃消息。原始消息为:{}", msg);
|
||||
}
|
||||
} catch (IOException ex) {
|
||||
log.error("消息确认失败: {}", ex.getMessage(), ex);
|
||||
}
|
||||
throw new RuntimeException("Failed to parse JSON to Map", e);
|
||||
}
|
||||
}
|
||||
|
||||
// 辅助方法:验证字符串是否为合法 JSON
|
||||
private static boolean isValidJson(String json) {
|
||||
try {
|
||||
new ObjectMapper().readTree(json);
|
||||
return true;
|
||||
} catch (Exception e) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
private void processDesignBatchResult(Message msg, Channel channel) {
|
||||
log.info("============processDesignBatchResult listening==========");
|
||||
long start = System.currentTimeMillis();
|
||||
|
||||
Map<String, Object> generateResult = JSONObject.parseObject(msg.getBody(), Map.class);
|
||||
log.info("designBatch response : {}", generateResult);
|
||||
designService.processDesignBatch(generateResult);
|
||||
}
|
||||
|
||||
private void processToProductImageBatchResult(Message msg, Channel channel) {
|
||||
log.info("============processToProductImageResultBatch listening==========");
|
||||
long start = System.currentTimeMillis();
|
||||
|
||||
JSONObject generateResult = JSONObject.parseObject(msg.getBody(), JSONObject.class);
|
||||
log.info("toProductImageBatch response : {}", generateResult);
|
||||
|
||||
try {
|
||||
log.info("task_id : {} start ", generateResult.get("task_id"));
|
||||
if (!StringUtils.isEmpty(generateResult.getString("progress"))) {
|
||||
String progress = generateResult.getString("progress");
|
||||
String url = null;
|
||||
if (!progress.startsWith("0") && !progress.equals("OK")) {
|
||||
JSONObject result = generateResult.getJSONObject("result");
|
||||
if (Objects.nonNull(result)) {
|
||||
url = result.getString("product_img");
|
||||
String taskId = generateResult.getString("task_id");
|
||||
userLikeGroupService.toProductBatch(taskId, url, progress);
|
||||
}
|
||||
} else if (progress.startsWith("0/")) {
|
||||
String batchTaskId = generateResult.getString("task_id");
|
||||
if (!StringUtils.isEmpty(batchTaskId)) {
|
||||
cloudTaskService.startTask(batchTaskId);
|
||||
}
|
||||
} else if (progress.equals("OK")) {
|
||||
String batchTaskId = generateResult.getString("task_id");
|
||||
if (!StringUtils.isEmpty(batchTaskId)) {
|
||||
cloudTaskService.completeTask(batchTaskId);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// 修改redis中的数据状态为exception
|
||||
String key = toProductImageResultKey + ":" + generateResult.get("task_id");
|
||||
generateService.updateToProductTaskStatus(generateResult.getString("task_id"), "Fail");
|
||||
redisUtil.addToString(key, new Gson().toJson(new GenerateResultVO(generateResult.getString("tasks_id"), null, null, "Fail")), CommonConstant.GENERATE_RESULT_EXPIRE_TIME);
|
||||
// 将异常信息存到exception中
|
||||
HashMap<String, String> exceptionInfo = new HashMap<>();
|
||||
exceptionInfo.put(generateResult.getString("task_id"), generateResult.getString("data"));
|
||||
// 存redis
|
||||
redisUtil.addToMap(exceptionMapKey, exceptionInfo);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
log.error(e.getMessage());
|
||||
try {
|
||||
channel.basicAck(msg.getMessageProperties().getDeliveryTag(), false);
|
||||
// 将消息从redis排队队列中删除,需保证被消费的消息存储到db之后再从redis删除
|
||||
redisUtil.removeFromZSet(consumptionOrderKey, generateResult.getString("task_id"));
|
||||
} catch (IOException exception) {
|
||||
log.error("手动确认,取消返回队列,不再重新消费");
|
||||
}
|
||||
// 将入参和错误信息存入数据库
|
||||
String exceptionMessage = JSONObject.toJSONString(generateResult) +
|
||||
" Exception message : " + e.getMessage();
|
||||
HashMap<String, String> exceptionInfo = new HashMap<>();
|
||||
exceptionInfo.put(String.valueOf(generateResult.get("task_id")), exceptionMessage);
|
||||
// 存redis
|
||||
redisUtil.addToMap(exceptionMapKey, exceptionInfo);
|
||||
}
|
||||
|
||||
long end = System.currentTimeMillis();
|
||||
log.info("task_id : {}, end , message : {}, 执行时长: {} 毫秒", generateResult.get("task_id"), generateResult.get("message"), (end - start));
|
||||
log.info("============ProcessToProductImageBatchResult End listening==========");
|
||||
}
|
||||
|
||||
private void processRelightBatchResult(Message msg, Channel channel) {
|
||||
log.info("============processRelightResult listening==========");
|
||||
long start = System.currentTimeMillis();
|
||||
|
||||
JSONObject generateResult = JSONObject.parseObject(msg.getBody(), JSONObject.class);
|
||||
log.info("relightBatch response : {}", generateResult);
|
||||
|
||||
try {
|
||||
log.info("task_id : {} start ", generateResult.get("task_id"));
|
||||
if (!StringUtils.isEmpty(generateResult.getString("progress"))) {
|
||||
String progress = generateResult.getString("progress");
|
||||
String url = null;
|
||||
if (!progress.startsWith("0") && !progress.equals("OK")) {
|
||||
JSONObject result = generateResult.getJSONObject("result");
|
||||
if (Objects.nonNull(result)) {
|
||||
url = result.getString("relight_img");
|
||||
String taskId = generateResult.getString("task_id");
|
||||
userLikeGroupService.relightBatch(taskId, url, progress);
|
||||
}
|
||||
} else if (progress.startsWith("0/")) {
|
||||
String batchTaskId = generateResult.getString("task_id");
|
||||
if (!StringUtils.isEmpty(batchTaskId)) {
|
||||
cloudTaskService.startTask(batchTaskId);
|
||||
}
|
||||
} else if (progress.equals("OK")) {
|
||||
String batchTaskId = generateResult.getString("task_id");
|
||||
if (!StringUtils.isEmpty(batchTaskId)) {
|
||||
cloudTaskService.completeTask(batchTaskId);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// 修改redis中的数据状态为exception
|
||||
String key = relightResultKey + ":" + generateResult.get("task_id");
|
||||
generateService.updateToProductTaskStatus(generateResult.getString("task_id"), "Fail");
|
||||
redisUtil.addToString(key, new Gson().toJson(new GenerateResultVO(generateResult.getString("tasks_id"), null, null, "Fail")), CommonConstant.GENERATE_RESULT_EXPIRE_TIME);
|
||||
// 将异常信息存到exception中
|
||||
HashMap<String, String> exceptionInfo = new HashMap<>();
|
||||
exceptionInfo.put(generateResult.getString("task_id"), generateResult.getString("data"));
|
||||
// 存redis
|
||||
redisUtil.addToMap(exceptionMapKey, exceptionInfo);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
log.error(e.getMessage());
|
||||
try {
|
||||
channel.basicAck(msg.getMessageProperties().getDeliveryTag(), false);
|
||||
// 将消息从redis排队队列中删除,需保证被消费的消息存储到db之后再从redis删除
|
||||
redisUtil.removeFromZSet(consumptionOrderKey, generateResult.getString("task_id"));
|
||||
} catch (IOException exception) {
|
||||
log.error("手动确认,取消返回队列,不再重新消费");
|
||||
}
|
||||
// 将入参和错误信息存入数据库
|
||||
String exceptionMessage = JSONObject.toJSONString(generateResult) +
|
||||
" Exception message : " + e.getMessage();
|
||||
HashMap<String, String> exceptionInfo = new HashMap<>();
|
||||
exceptionInfo.put(String.valueOf(generateResult.get("task_id")), exceptionMessage);
|
||||
// 存redis
|
||||
redisUtil.addToMap(exceptionMapKey, exceptionInfo);
|
||||
}
|
||||
|
||||
long end = System.currentTimeMillis();
|
||||
log.info("task_id : {}, end , message : {}, 执行时长: {} 毫秒", generateResult.get("task_id"), generateResult.get("message"), (end - start));
|
||||
log.info("============ProcessRelightBatchResult End listening==========");
|
||||
}
|
||||
|
||||
private void processPoseTransformBatchResult(Message msg, Channel channel) {
|
||||
log.info("============ProcessPoseTransformBatchResult listening==========");
|
||||
long start = System.currentTimeMillis();
|
||||
|
||||
JSONObject generateResult = JSONObject.parseObject(msg.getBody(), JSONObject.class);
|
||||
log.info("PoseTransformationBatch response : {}", generateResult);
|
||||
|
||||
try {
|
||||
log.info("task_id : {} start ", generateResult.get("task_id"));
|
||||
if (!StringUtils.isEmpty(generateResult.getString("progress"))) {
|
||||
String progress = generateResult.getString("progress");
|
||||
String taskId = generateResult.getString("task_id");
|
||||
generateService.processPoseTransformResultBatch(progress, taskId);
|
||||
|
||||
JSONArray result = generateResult.getJSONArray("result");
|
||||
if (!StringUtils.isEmpty(result)) {
|
||||
JSONObject jsonObject = result.getJSONObject(0);
|
||||
String gifUrl = jsonObject.getString("gif_url");
|
||||
String videoUrl = jsonObject.getString("video_url");
|
||||
String imageUrl = jsonObject.getString("first_image_url");
|
||||
generateService.processPoseTransformResultBatch(taskId, gifUrl, videoUrl, imageUrl, progress);
|
||||
}
|
||||
} else {
|
||||
// 修改redis中的数据状态为exception
|
||||
String key = generateResultKey + ":" + generateResult.getString("task_id");
|
||||
generateService.updatePoseTransferStatus(generateResult.getString("task_id"), "Fail", null);
|
||||
redisUtil.addToString(key, new Gson().toJson(new PoseTransformationVO(null, generateResult.getString("task_id"),null, null, null, (byte)0, "Fail")), CommonConstant.GENERATE_RESULT_EXPIRE_TIME);
|
||||
// 将异常信息存到exception中
|
||||
HashMap<String, String> exceptionInfo = new HashMap<>();
|
||||
exceptionInfo.put(generateResult.getString("task_id"), generateResult.getString("message"));
|
||||
// 存redis
|
||||
redisUtil.addToMap(exceptionMapKey, exceptionInfo);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
log.error(e.getMessage());
|
||||
try {
|
||||
channel.basicAck(msg.getMessageProperties().getDeliveryTag(), false);
|
||||
// 将消息从redis排队队列中删除,需保证被消费的消息存储到db之后再从redis删除
|
||||
redisUtil.removeFromZSet(consumptionOrderKey, generateResult.getString("task_id"));
|
||||
} catch (IOException exception) {
|
||||
log.error("手动确认,取消返回队列,不再重新消费");
|
||||
}
|
||||
// 将入参和错误信息存入数据库
|
||||
String exceptionMessage = JSONObject.toJSONString(generateResult) +
|
||||
" Exception message : " + e.getMessage();
|
||||
HashMap<String, String> exceptionInfo = new HashMap<>();
|
||||
exceptionInfo.put(generateResult.getString("task_id"), exceptionMessage);
|
||||
// 存redis
|
||||
redisUtil.addToMap(exceptionMapKey, exceptionInfo);
|
||||
}
|
||||
|
||||
long end = System.currentTimeMillis();
|
||||
log.info("tasks_id : {}, end , message : {}, 执行时长: {} 毫秒", generateResult.get("tasks_id"), generateResult.get("message"), (end - start));
|
||||
log.info("============ProcessPoseTransformResult End listening==========");
|
||||
}
|
||||
|
||||
@RabbitListener(queues = "#{rabbitMQProperties.queues.generate}")
|
||||
@RabbitHandler
|
||||
public void generateConsumer1(Message msg, Channel channel) {
|
||||
generate(msg, channel, "consumer 1");
|
||||
}
|
||||
|
||||
@RabbitListener(queues = "#{rabbitMQProperties.queues.generate}")
|
||||
@RabbitHandler
|
||||
public void generateConsumer2(Message msg, Channel channel) {
|
||||
generate(msg, channel, "consumer 2");
|
||||
}
|
||||
|
||||
@RabbitListener(queues = "#{rabbitMQProperties.queues.generate}")
|
||||
@RabbitHandler
|
||||
public void generateConsumer3(Message msg, Channel channel) {
|
||||
generate(msg, channel, "consumer 3");
|
||||
}
|
||||
|
||||
@RabbitListener(queues = "#{rabbitMQProperties.queues.generate}")
|
||||
@RabbitHandler
|
||||
public void generateConsumer4(Message msg, Channel channel) {
|
||||
generate(msg, channel, "consumer 4");
|
||||
}
|
||||
|
||||
@RabbitListener(queues = "#{rabbitMQProperties.queues.generate}")
|
||||
@RabbitHandler
|
||||
public void generateConsumer5(Message msg, Channel channel) {
|
||||
generate(msg, channel, "consumer 5");
|
||||
}
|
||||
|
||||
@RabbitListener(queues = "#{rabbitMQProperties.queues.generate}")
|
||||
@RabbitHandler
|
||||
public void generateConsumer6(Message msg, Channel channel) {
|
||||
generate(msg, channel, "consumer 6");
|
||||
}
|
||||
|
||||
@RabbitListener(queues = "#{rabbitMQProperties.queues.generate}")
|
||||
@RabbitHandler
|
||||
public void generateConsumer7(Message msg, Channel channel) {
|
||||
generate(msg, channel, "consumer 7");
|
||||
}
|
||||
|
||||
@RabbitListener(queues = "#{rabbitMQProperties.queues.generate}")
|
||||
@RabbitHandler
|
||||
public void generateConsumer8(Message msg, Channel channel) {
|
||||
generate(msg, channel, "consumer 8");
|
||||
}
|
||||
|
||||
@RabbitListener(queues = "#{rabbitMQProperties.queues.generate}")
|
||||
@RabbitHandler
|
||||
public void generateConsumer9(Message msg, Channel channel) {
|
||||
generate(msg, channel, "consumer 9");
|
||||
}
|
||||
|
||||
@RabbitListener(queues = "#{rabbitMQProperties.queues.generateResult}")
|
||||
@RabbitHandler
|
||||
public void getGenerateResult(Message msg, Channel channel) {
|
||||
processGenerateResult(msg, channel);
|
||||
}
|
||||
|
||||
@RabbitListener(queues = "#{rabbitMQProperties.queues.toProductImageResult}")
|
||||
@RabbitHandler
|
||||
public void getToProductImageResult(Message msg, Channel channel) {
|
||||
processToProductImageResult(msg, channel);
|
||||
}
|
||||
|
||||
@RabbitListener(queues = "#{rabbitMQProperties.queues.relightResult}")
|
||||
@RabbitHandler
|
||||
public void getRelightResult(Message msg, Channel channel) {
|
||||
processRelightResult(msg, channel);
|
||||
}
|
||||
|
||||
@RabbitListener(queues = "#{rabbitMQProperties.queues.poseTransform}")
|
||||
@RabbitHandler
|
||||
public void getPoseTransformationResult(Message msg, Channel channel) {
|
||||
processPoseTransformResult(msg, channel);
|
||||
}
|
||||
// @RabbitListener(queues = "#{rabbitMQProperties.queues.designBatch}")
|
||||
// @RabbitHandler
|
||||
// public void getDesignBatchResult(Message msg, Channel channel) {
|
||||
// processDesignBatchResult(msg, channel);
|
||||
// }
|
||||
// @RabbitListener(queues = "#{rabbitMQProperties.queues.toProductImageBatch}")
|
||||
// @RabbitHandler
|
||||
// public void getToProductImageBatchResult(Message msg, Channel channel) {
|
||||
// processToProductImageBatchResult(msg, channel);
|
||||
// }
|
||||
//
|
||||
// @RabbitListener(queues = "#{rabbitMQProperties.queues.relightBatch}")
|
||||
// @RabbitHandler
|
||||
// public void getRelightBatchResult(Message msg, Channel channel) {
|
||||
// processRelightBatchResult(msg, channel);
|
||||
// }
|
||||
//
|
||||
// @RabbitListener(queues = "#{rabbitMQProperties.queues.poseTransformBatch}")
|
||||
// @RabbitHandler
|
||||
// public void getPoseTransformBatchResult(Message msg, Channel channel) {
|
||||
// processPoseTransformBatchResult(msg, channel);
|
||||
// }
|
||||
}
|
||||
82
src/main/java/com/ai/da/common/RabbitMQ/MQConfig.java
Normal file
82
src/main/java/com/ai/da/common/RabbitMQ/MQConfig.java
Normal file
@@ -0,0 +1,82 @@
|
||||
package com.ai.da.common.RabbitMQ;
|
||||
|
||||
import org.springframework.amqp.core.*;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
|
||||
@Configuration
|
||||
public class MQConfig {
|
||||
|
||||
@Autowired
|
||||
private RabbitMQProperties rabbitMQProperties;
|
||||
|
||||
@Bean
|
||||
public Queue generateQueue() {
|
||||
return new Queue(rabbitMQProperties.getQueues().getGenerate());
|
||||
}
|
||||
|
||||
@Bean
|
||||
public Queue SRQueue() {
|
||||
return new Queue(rabbitMQProperties.getQueues().getSr());
|
||||
}
|
||||
|
||||
@Bean
|
||||
public Queue SRResultQueue() {
|
||||
return new Queue(rabbitMQProperties.getQueues().getSrResult());
|
||||
}
|
||||
|
||||
@Bean
|
||||
public Queue generateResultQueue() {
|
||||
return new Queue(rabbitMQProperties.getQueues().getGenerateResult());
|
||||
}
|
||||
|
||||
@Bean
|
||||
public Queue toProductImageResultQueue() {
|
||||
return new Queue(rabbitMQProperties.getQueues().getToProductImageResult());
|
||||
}
|
||||
|
||||
@Bean
|
||||
public Queue relightResultQueue() {
|
||||
return new Queue(rabbitMQProperties.getQueues().getRelightResult());
|
||||
}
|
||||
|
||||
@Bean
|
||||
public Queue poseTransformQueue() {
|
||||
return new Queue(rabbitMQProperties.getQueues().getPoseTransform());
|
||||
}
|
||||
|
||||
@Bean
|
||||
public Queue mailRetryQueue() {
|
||||
// 普通队列,不绑定DLX(首次失败后才进入MQ)
|
||||
// durable 持久化队列
|
||||
return QueueBuilder.durable(rabbitMQProperties.getQueues().getEmailRetry())
|
||||
// 关键参数:绑定死信交换机
|
||||
.withArgument("x-dead-letter-exchange", rabbitMQProperties.getDeadLetter().getExchange())
|
||||
// 可选:指定死信路由键(默认使用原消息的路由键)
|
||||
.withArgument("x-dead-letter-routing-key", rabbitMQProperties.getDeadLetter().getRoutingKey())
|
||||
.build();
|
||||
}
|
||||
|
||||
// 新增死信交换机
|
||||
@Bean
|
||||
public DirectExchange deadLetterExchange() {
|
||||
return new DirectExchange(rabbitMQProperties.getDeadLetter().getExchange());
|
||||
}
|
||||
|
||||
// 新增死信队列
|
||||
@Bean
|
||||
public Queue deadLetterQueue() {
|
||||
return QueueBuilder.durable(rabbitMQProperties.getDeadLetter().getQueue()).build();
|
||||
}
|
||||
|
||||
// 绑定死信队列
|
||||
@Bean
|
||||
public Binding deadLetterBinding() {
|
||||
return BindingBuilder.bind(deadLetterQueue())
|
||||
.to(deadLetterExchange())
|
||||
.with(rabbitMQProperties.getDeadLetter().getRoutingKey());
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
61
src/main/java/com/ai/da/common/RabbitMQ/MQPublisher.java
Normal file
61
src/main/java/com/ai/da/common/RabbitMQ/MQPublisher.java
Normal file
@@ -0,0 +1,61 @@
|
||||
package com.ai.da.common.RabbitMQ;
|
||||
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.amqp.core.AmqpTemplate;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import jakarta.annotation.Resource;
|
||||
import java.util.Map;
|
||||
|
||||
@Slf4j
|
||||
@Component
|
||||
public class MQPublisher {
|
||||
|
||||
@Autowired
|
||||
private RabbitMQProperties rabbitMQProperties;
|
||||
|
||||
@Autowired
|
||||
private AmqpTemplate amqpTemplate;
|
||||
|
||||
public void sendGenerateMessage(String mm) {
|
||||
log.info("send generate message: {}", mm);
|
||||
amqpTemplate.convertAndSend(rabbitMQProperties.getQueues().getGenerate(), mm);
|
||||
}
|
||||
|
||||
public void sendSRMessage(String mm) {
|
||||
log.info("send message: {}", mm);
|
||||
amqpTemplate.convertAndSend(rabbitMQProperties.getQueues().getSr(), mm);
|
||||
}
|
||||
|
||||
public void sendGenerateResultMessage(String mm) {
|
||||
log.info("send generate result message: {}", mm);
|
||||
amqpTemplate.convertAndSend(rabbitMQProperties.getQueues().getGenerateResult(), mm);
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param mailParams 含有的字段
|
||||
* {"dto": basicEmailParamDTO, "filename": fileName, "source": inputStreamSource,
|
||||
* "templateParams": jsonObject, "templatePath": path}
|
||||
* 邮件发送参数,附件文件名,附件数据
|
||||
* @param retryTimes 重试次数(初始为0)
|
||||
*/
|
||||
public void sendEmailMsg(Map<String, String> mailParams, int retryTimes){
|
||||
log.info("send email MQ message: {} ", mailParams);
|
||||
// // 重新入队(指数退避) 时间单位:毫秒
|
||||
long newDelay = (long) (5000 * Math.pow(2, retryTimes + 1));
|
||||
log.info("send email MQ delay: {} ms, retry attempt: {}", newDelay, retryTimes + 1);
|
||||
amqpTemplate.convertAndSend(
|
||||
rabbitMQProperties.getQueues().getEmailRetry(),
|
||||
mailParams,
|
||||
m -> {
|
||||
m.getMessageProperties().setExpiration(String.valueOf(newDelay));
|
||||
m.getMessageProperties().setHeader("x-retry-attempt", retryTimes + 1);
|
||||
return m;
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@@ -0,0 +1,45 @@
|
||||
package com.ai.da.common.RabbitMQ;
|
||||
|
||||
import lombok.Data;
|
||||
import org.springframework.boot.context.properties.ConfigurationProperties;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
@Component
|
||||
@ConfigurationProperties(prefix = "rabbitmq")
|
||||
@Data
|
||||
public class RabbitMQProperties {
|
||||
|
||||
private Queues queues;
|
||||
private Exchange exchange;
|
||||
private DeadLetter deadLetter; // 新增死信配置
|
||||
|
||||
@Data
|
||||
public static class Queues {
|
||||
private String generate;
|
||||
private String sr;
|
||||
private String srResult;
|
||||
private String generateResult;
|
||||
private String toProductImageResult;
|
||||
private String relightResult;
|
||||
private String poseTransform;
|
||||
private String emailRetry;
|
||||
private String designBatch;
|
||||
private String relightBatch;
|
||||
private String toProductImageBatch;
|
||||
private String poseTransformBatch;
|
||||
}
|
||||
|
||||
@Data
|
||||
public static class Exchange {
|
||||
private String generate;
|
||||
}
|
||||
|
||||
// 新增死信配置内部类
|
||||
@Data
|
||||
public static class DeadLetter {
|
||||
private String exchange;
|
||||
private String queue;
|
||||
private String routingKey;
|
||||
}
|
||||
}
|
||||
|
||||
237
src/main/java/com/ai/da/common/RabbitMQ/SRConsumer.java
Normal file
237
src/main/java/com/ai/da/common/RabbitMQ/SRConsumer.java
Normal file
@@ -0,0 +1,237 @@
|
||||
package com.ai.da.common.RabbitMQ;
|
||||
|
||||
import com.ai.da.common.config.exception.BusinessException;
|
||||
import com.ai.da.common.utils.RedisUtil;
|
||||
import com.ai.da.model.dto.SuperResolutionDTO;
|
||||
import com.ai.da.model.dto.TaskDTO;
|
||||
import com.ai.da.service.SuperResolutionService;
|
||||
import com.ai.da.service.TaskListService;
|
||||
import com.alibaba.fastjson.JSONException;
|
||||
import com.alibaba.fastjson.JSONObject;
|
||||
import com.google.gson.Gson;
|
||||
import com.google.gson.reflect.TypeToken;
|
||||
import com.rabbitmq.client.Channel;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.amqp.core.Message;
|
||||
import org.springframework.amqp.rabbit.annotation.RabbitHandler;
|
||||
import org.springframework.amqp.rabbit.annotation.RabbitListener;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import jakarta.annotation.Resource;
|
||||
import java.io.IOException;
|
||||
import java.lang.reflect.Type;
|
||||
import java.util.HashMap;
|
||||
|
||||
@Slf4j
|
||||
@Component
|
||||
public class SRConsumer {
|
||||
|
||||
@Autowired
|
||||
private RabbitMQProperties rabbitMQProperties;
|
||||
|
||||
@Resource
|
||||
private RedisUtil redisUtil;
|
||||
|
||||
@Resource
|
||||
private TaskListService taskListService;
|
||||
|
||||
@Value("${redis.key.orderForSR}")
|
||||
private String consumptionOrderKey;
|
||||
|
||||
@Value("${redis.key.SRCancelSet}")
|
||||
private String cancelSetKey;
|
||||
|
||||
@Value("${redis.key.SRExceptionMap}")
|
||||
private String exceptionMapKey;
|
||||
|
||||
@Value("${redis.key.taskList}")
|
||||
private String taskListKey;
|
||||
|
||||
@Resource
|
||||
private SuperResolutionService superResolutionService;
|
||||
|
||||
/**
|
||||
* 请求超分处理
|
||||
*/
|
||||
public void superResolution(Message msg, Channel channel, String consumerName) {
|
||||
log.info("============SR start listening==========");
|
||||
long start = System.currentTimeMillis();
|
||||
|
||||
SuperResolutionDTO superResolutionDTO;
|
||||
String uniqueId = null;
|
||||
|
||||
try {
|
||||
superResolutionDTO = JSONObject.parseObject(msg.getBody(), SuperResolutionDTO.class);
|
||||
uniqueId = superResolutionDTO.getUniqueId();
|
||||
log.info("From " + consumerName + " : " + uniqueId);
|
||||
superResolutionService.updateSROutput(uniqueId, "Executing", null);
|
||||
taskListService.updateTaskStatusOrOutputRedis(uniqueId, "Executing", null);
|
||||
/*try {
|
||||
Thread.sleep(2 * 60 * 1000);
|
||||
} catch (InterruptedException e) {
|
||||
throw new RuntimeException(e);
|
||||
}*/
|
||||
// 2、判断当前消息是否在取消列表中
|
||||
Boolean isMember = redisUtil.isElementExistsInSet(cancelSetKey, uniqueId);
|
||||
if (isMember) {
|
||||
try {
|
||||
// 2.1 手动确认该消息
|
||||
channel.basicAck(msg.getMessageProperties().getDeliveryTag(), false);
|
||||
} catch (IOException ex) {
|
||||
log.error("手动确认,不返回队列重新消费");
|
||||
}
|
||||
} else {
|
||||
// 请求python端进行超分
|
||||
superResolutionService.SR(superResolutionDTO);
|
||||
}
|
||||
} catch (BusinessException e) {
|
||||
log.error(e.getMsg());
|
||||
superResolutionDTO = JSONObject.parseObject(msg.getBody(), SuperResolutionDTO.class);
|
||||
// channel.basicNack() 为不确认deliveryTag对应的消息,第二个参数是否应用于多消息,第三个参数是否requeue
|
||||
setErrorMessage(msg, channel, e.getMsg(), superResolutionDTO);
|
||||
try {
|
||||
// 2.1 手动确认该消息
|
||||
channel.basicAck(msg.getMessageProperties().getDeliveryTag(), false);
|
||||
} catch (IOException ex) {
|
||||
log.error("手动确认,不返回队列重新消费, error message : " + e.getMessage());
|
||||
}
|
||||
} catch (JSONException e) {
|
||||
log.error(e.getMessage());
|
||||
setErrorMessage(msg, channel, e.getMessage(), null);
|
||||
try {
|
||||
// 2.1 手动确认该消息
|
||||
channel.basicAck(msg.getMessageProperties().getDeliveryTag(), false);
|
||||
} catch (IOException ex) {
|
||||
log.error("手动确认,不返回队列重新消费, error message : " + e.getMessage());
|
||||
}
|
||||
} catch (Exception e) {
|
||||
log.error(e.getMessage());
|
||||
superResolutionDTO = JSONObject.parseObject(msg.getBody(), SuperResolutionDTO.class);
|
||||
setErrorMessage(msg, channel, e.getMessage(), superResolutionDTO);
|
||||
try {
|
||||
// 2.1 手动确认该消息
|
||||
channel.basicAck(msg.getMessageProperties().getDeliveryTag(), false);
|
||||
} catch (IOException ex) {
|
||||
log.error("手动确认,不返回队列重新消费, error message : " + e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
long end = System.currentTimeMillis();
|
||||
|
||||
log.info(" task_id: " + uniqueId + "----------" + consumerName + " 执行时长:" + (end - start) + "毫秒");
|
||||
log.info("=============SR end listening===========");
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取超分结果
|
||||
*/
|
||||
public void getSRResult(Message msg, Channel channel, String consumerName) {
|
||||
log.info("============SRResult start listening==========");
|
||||
long start = System.currentTimeMillis();
|
||||
|
||||
JSONObject result = null;
|
||||
String taskId = null;
|
||||
|
||||
try {
|
||||
result = JSONObject.parseObject(msg.getBody(), JSONObject.class);
|
||||
log.info("SR response : {}", result);
|
||||
taskId = result.get("tasks_id").toString();
|
||||
} catch (JSONException e) {
|
||||
log.error("SRResult 返回数据格式不合规范");
|
||||
log.error(e.getMessage());
|
||||
setErrorMessage(msg, channel, e.getMessage(), null);
|
||||
try {
|
||||
// 第二个参数,是否批量确认消息,当传false时,只确认当前 deliveryTag对应的消息;当传true时,会确认当前及之前所有未确认的消息。
|
||||
channel.basicAck(msg.getMessageProperties().getDeliveryTag(), false);
|
||||
} catch (IOException exception) {
|
||||
log.error("手动确认,取消返回队列,不再重新消费");
|
||||
}
|
||||
} catch (Exception e){
|
||||
log.error(e.getMessage());
|
||||
setErrorMessage(msg, channel, e.getMessage(), null);
|
||||
try {
|
||||
// 第二个参数,是否批量确认消息,当传false时,只确认当前 deliveryTag对应的消息;当传true时,会确认当前及之前所有未确认的消息。
|
||||
channel.basicAck(msg.getMessageProperties().getDeliveryTag(), false);
|
||||
} catch (IOException exception) {
|
||||
log.error("手动确认,取消返回队列,不再重新消费");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
try {
|
||||
// 2、判断状态是否成功
|
||||
if ("SUCCESS".equals(result.get("status").toString())) {
|
||||
String output = result.get("data").toString();
|
||||
superResolutionService.setSRResult(taskId, output, "success");
|
||||
taskListService.updateTaskStatusOrOutputRedis(taskId, "success", output);
|
||||
} else {
|
||||
superResolutionService.setSRResult(taskId, null, "fail");
|
||||
taskListService.updateTaskStatusOrOutputRedis(taskId, "fail", null);
|
||||
HashMap<String, String> exceptionInfo = new HashMap<>();
|
||||
// 获取输入信息
|
||||
String task = redisUtil.getFromString(taskListKey + taskId + taskId.substring(taskId.lastIndexOf("-") + 1));
|
||||
Gson gson = new Gson();
|
||||
Type type = new TypeToken<TaskDTO<SuperResolutionDTO>>() {
|
||||
}.getType();
|
||||
TaskDTO<SuperResolutionDTO> taskDTO = gson.fromJson(task, type);
|
||||
// 将输入信息和报错信息均存入redis todo 加判空
|
||||
exceptionInfo.put(taskId, "Input ==> " + taskDTO.getInputParam() + "Fail Message ==> " + result.get("message").toString());
|
||||
// 将报错信息存入redis
|
||||
redisUtil.addToMap(exceptionMapKey, exceptionInfo);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
log.error(e.getMessage());
|
||||
// channel.basicNack() 为不确认deliveryTag对应的消息,第二个参数是否应用于多消息,第三个参数是否requeue
|
||||
try {
|
||||
// 第二个参数,是否批量确认消息,当传false时,只确认当前 deliveryTag对应的消息;当传true时,会确认当前及之前所有未确认的消息。
|
||||
channel.basicAck(msg.getMessageProperties().getDeliveryTag(), false);
|
||||
} catch (IOException exception) {
|
||||
log.error("手动确认,取消返回队列,不再重新消费");
|
||||
}
|
||||
}
|
||||
|
||||
long end = System.currentTimeMillis();
|
||||
|
||||
log.info(" task_id: " + taskId + "----------" + consumerName + " 执行时长:" + (end - start) + "毫秒");
|
||||
log.info("=============SRResult end listening===========");
|
||||
}
|
||||
|
||||
private void setErrorMessage(Message msg, Channel channel, String message, SuperResolutionDTO superResolutionDTO) {
|
||||
String uniqueId;
|
||||
try {
|
||||
// 第二个参数,是否批量确认消息,当传false时,只确认当前 deliveryTag对应的消息;当传true时,会确认当前及之前所有未确认的消息。
|
||||
channel.basicAck(msg.getMessageProperties().getDeliveryTag(), false);
|
||||
uniqueId = superResolutionDTO.getUniqueId();
|
||||
// 将消息从redis排队队列中删除,需保证被消费的消息存储到db之后再从redis删除
|
||||
redisUtil.removeFromZSet(consumptionOrderKey, uniqueId);
|
||||
} catch (Exception exception) {
|
||||
log.error("手动确认,取消返回队列,不再重新消费");
|
||||
throw new BusinessException("message.confirm.fail");
|
||||
}
|
||||
// 将入参和错误信息存入redis
|
||||
String exceptionMessage = JSONObject.toJSONString(superResolutionDTO) +
|
||||
" Exception message : " + message;
|
||||
// " Exception message : " + e.getMessage();
|
||||
HashMap<String, String> exceptionInfo = new HashMap<>();
|
||||
uniqueId = superResolutionDTO.getUniqueId();
|
||||
exceptionInfo.put(String.valueOf(uniqueId), exceptionMessage);
|
||||
// 存redis
|
||||
redisUtil.addToMap(exceptionMapKey, exceptionInfo);
|
||||
taskListService.updateTaskStatusOrOutputRedis(uniqueId, "fail", null);
|
||||
}
|
||||
|
||||
@RabbitListener(queues = "#{rabbitMQProperties.queues.sr}")
|
||||
@RabbitHandler
|
||||
public void SRConsumer1(Message msg, Channel channel) {
|
||||
superResolution(msg, channel, "consumer 1");
|
||||
}
|
||||
|
||||
@RabbitListener(queues = "#{rabbitMQProperties.queues.srResult}")
|
||||
@RabbitHandler
|
||||
public void SRResultConsumer1(Message msg, Channel channel) {
|
||||
getSRResult(msg, channel, "consumer 1");
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,170 @@
|
||||
package com.ai.da.common.aspect;
|
||||
|
||||
import com.ai.da.common.context.UserContext;
|
||||
import com.ai.da.model.vo.AuthPrincipalVo;
|
||||
import jakarta.servlet.http.HttpServletRequest;
|
||||
import jakarta.servlet.http.HttpServletResponse;
|
||||
import org.aspectj.lang.JoinPoint;
|
||||
import org.aspectj.lang.annotation.*;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.stereotype.Component;
|
||||
import org.springframework.web.context.request.RequestContextHolder;
|
||||
import org.springframework.web.context.request.ServletRequestAttributes;
|
||||
import org.springframework.web.multipart.MultipartFile;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* Controller日志切面
|
||||
* 记录所有Controller接口的请求参数和用户信息
|
||||
*/
|
||||
@Aspect
|
||||
@Component
|
||||
public class ControllerLoggingAspect {
|
||||
|
||||
private static final Logger logger = LoggerFactory.getLogger(ControllerLoggingAspect.class);
|
||||
|
||||
/**
|
||||
* 定义切点:所有Controller方法
|
||||
*/
|
||||
@Pointcut("execution(* com.ai.da.controller..*(..))")
|
||||
public void controllerMethods() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Controller方法执行前记录日志
|
||||
*/
|
||||
// @Before("controllerMethods()")
|
||||
public void logControllerBefore(JoinPoint joinPoint) {
|
||||
ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
|
||||
if (attributes != null) {
|
||||
HttpServletRequest request = attributes.getRequest();
|
||||
|
||||
// 获取当前用户ID
|
||||
Long userId = null;
|
||||
AuthPrincipalVo authPrincipalVo = UserContext.getUserHolder();
|
||||
if (authPrincipalVo != null) {
|
||||
userId = authPrincipalVo.getId();
|
||||
}
|
||||
|
||||
// 获取请求参数
|
||||
Map<String, Object> params = getRequestParams(joinPoint, request);
|
||||
|
||||
logger.info("=== 请求开始 ===");
|
||||
logger.info("用户ID: {}", userId);
|
||||
logger.info("请求URL: {}", request.getRequestURL().toString());
|
||||
logger.info("请求方法: {}", request.getMethod());
|
||||
logger.info("请求IP: {}", getClientIpAddress(request));
|
||||
logger.info("调用方法: {}.{}", joinPoint.getSignature().getDeclaringType().getSimpleName(), joinPoint.getSignature().getName());
|
||||
logger.info("请求参数: {}", params);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取请求参数
|
||||
*/
|
||||
private Map<String, Object> getRequestParams(JoinPoint joinPoint, HttpServletRequest request) {
|
||||
Map<String, Object> params = new HashMap<>();
|
||||
|
||||
// 1. 获取Query String参数
|
||||
String queryString = request.getQueryString();
|
||||
if (queryString != null && !queryString.isEmpty()) {
|
||||
params.put("queryString", queryString);
|
||||
}
|
||||
|
||||
// 2. 获取方法参数(包含 @PathVariable, @RequestParam, @RequestBody 等)
|
||||
Object[] args = joinPoint.getArgs();
|
||||
|
||||
if (args != null && args.length > 0) {
|
||||
Map<String, Object> methodParams = new HashMap<>();
|
||||
for (int i = 0; i < args.length; i++) {
|
||||
Object arg = args[i];
|
||||
// 过滤掉不可序列化的参数
|
||||
if (arg != null) {
|
||||
if (isIgnorable(arg)) {
|
||||
// 对于可忽略的类型,记录类型名
|
||||
methodParams.put("arg" + i, "[" + arg.getClass().getSimpleName() + "]");
|
||||
} else {
|
||||
try {
|
||||
methodParams.put("arg" + i, arg);
|
||||
} catch (Exception e) {
|
||||
methodParams.put("arg" + i, arg.toString());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!methodParams.isEmpty()) {
|
||||
params.put("methodParams", methodParams);
|
||||
}
|
||||
}
|
||||
|
||||
return params;
|
||||
}
|
||||
|
||||
/**
|
||||
* 判断是否需要过滤的参数类型
|
||||
*/
|
||||
private boolean isIgnorable(Object obj) {
|
||||
return obj instanceof HttpServletRequest
|
||||
|| obj instanceof HttpServletResponse
|
||||
|| obj instanceof MultipartFile
|
||||
|| obj instanceof MultipartFile[];
|
||||
}
|
||||
|
||||
/**
|
||||
* Controller方法抛出异常时记录日志
|
||||
*/
|
||||
@AfterThrowing(pointcut = "controllerMethods()", throwing = "exception")
|
||||
public void logControllerAfterThrowing(JoinPoint joinPoint, Throwable exception) {
|
||||
ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
|
||||
|
||||
Long userId = null;
|
||||
AuthPrincipalVo authPrincipalVo = UserContext.getUserHolder();
|
||||
if (authPrincipalVo != null) {
|
||||
userId = authPrincipalVo.getId();
|
||||
}
|
||||
|
||||
// 获取请求参数
|
||||
Map<String, Object> params = new HashMap<>();
|
||||
if (attributes != null) {
|
||||
HttpServletRequest request = attributes.getRequest();
|
||||
params = getRequestParams(joinPoint, request);
|
||||
}
|
||||
|
||||
logger.error("=== 请求异常 ===");
|
||||
logger.error("用户ID: {}", userId);
|
||||
logger.error("调用方法: {}.{}", joinPoint.getSignature().getDeclaringType().getSimpleName(), joinPoint.getSignature().getName());
|
||||
logger.error("请求参数: {}", params);
|
||||
logger.error("异常信息: ", exception);
|
||||
logger.error("=== 异常结束 ===");
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取客户端真实IP地址
|
||||
*/
|
||||
private String getClientIpAddress(HttpServletRequest request) {
|
||||
String xForwardedFor = request.getHeader("X-Forwarded-For");
|
||||
if (xForwardedFor != null && !xForwardedFor.isEmpty() && !"unknown".equalsIgnoreCase(xForwardedFor)) {
|
||||
return xForwardedFor.split(",")[0];
|
||||
}
|
||||
|
||||
String xRealIp = request.getHeader("X-Real-IP");
|
||||
if (xRealIp != null && !xRealIp.isEmpty() && !"unknown".equalsIgnoreCase(xRealIp)) {
|
||||
return xRealIp;
|
||||
}
|
||||
|
||||
String proxyClientIp = request.getHeader("Proxy-Client-IP");
|
||||
if (proxyClientIp != null && !proxyClientIp.isEmpty() && !"unknown".equalsIgnoreCase(proxyClientIp)) {
|
||||
return proxyClientIp;
|
||||
}
|
||||
|
||||
String wlProxyClientIp = request.getHeader("WL-Proxy-Client-IP");
|
||||
if (wlProxyClientIp != null && !wlProxyClientIp.isEmpty() && !"unknown".equalsIgnoreCase(wlProxyClientIp)) {
|
||||
return wlProxyClientIp;
|
||||
}
|
||||
|
||||
return request.getRemoteAddr();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,43 @@
|
||||
package com.ai.da.common.config;
|
||||
|
||||
import com.alipay.api.*;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.context.annotation.PropertySource;
|
||||
import org.springframework.core.env.Environment;
|
||||
|
||||
import jakarta.annotation.Resource;
|
||||
|
||||
@Configuration
|
||||
//加载配置文件
|
||||
@PropertySource("classpath:alipay-sandbox.properties")
|
||||
public class AlipayClientConfig {
|
||||
|
||||
@Resource
|
||||
private Environment config;
|
||||
|
||||
@Bean
|
||||
public AlipayClient alipayClient() throws AlipayApiException {
|
||||
|
||||
AlipayConfig alipayConfig = new AlipayConfig();
|
||||
|
||||
//设置网关地址
|
||||
alipayConfig.setServerUrl(config.getProperty("alipay.gateway-url"));
|
||||
//设置应用Id
|
||||
alipayConfig.setAppId(config.getProperty("alipay.app-id"));
|
||||
//设置应用私钥
|
||||
alipayConfig.setPrivateKey(config.getProperty("alipay.merchant-private-key"));
|
||||
//设置请求格式,固定值json
|
||||
alipayConfig.setFormat(AlipayConstants.FORMAT_JSON);
|
||||
//设置字符集
|
||||
alipayConfig.setCharset(AlipayConstants.CHARSET_UTF8);
|
||||
//设置支付宝公钥
|
||||
alipayConfig.setAlipayPublicKey(config.getProperty("alipay.alipay-public-key"));
|
||||
//设置签名类型
|
||||
alipayConfig.setSignType(AlipayConstants.SIGN_TYPE_RSA2);
|
||||
//构造client
|
||||
AlipayClient alipayClient = new DefaultAlipayClient(alipayConfig);
|
||||
|
||||
return alipayClient;
|
||||
}
|
||||
}
|
||||
21
src/main/java/com/ai/da/common/config/AsyncConfig.java
Normal file
21
src/main/java/com/ai/da/common/config/AsyncConfig.java
Normal file
@@ -0,0 +1,21 @@
|
||||
package com.ai.da.common.config;
|
||||
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
|
||||
|
||||
import java.util.concurrent.Executor;
|
||||
|
||||
@Configuration
|
||||
public class AsyncConfig {
|
||||
@Bean("asyncTaskExecutor")
|
||||
public Executor asyncTaskExecutor() {
|
||||
ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
|
||||
executor.setCorePoolSize(5);
|
||||
executor.setMaxPoolSize(10);
|
||||
executor.setQueueCapacity(100);
|
||||
executor.setThreadNamePrefix("Async-ImageToSketch-");
|
||||
executor.initialize();
|
||||
return executor;
|
||||
}
|
||||
}
|
||||
393
src/main/java/com/ai/da/common/config/CRMReportInterface.java
Normal file
393
src/main/java/com/ai/da/common/config/CRMReportInterface.java
Normal file
@@ -0,0 +1,393 @@
|
||||
package com.ai.da.common.config;
|
||||
|
||||
import com.ai.da.mapper.primary.entity.CustomerData;
|
||||
import com.ai.da.mapper.primary.entity.TransactionData;
|
||||
|
||||
import java.io.FileWriter;
|
||||
import java.io.IOException;
|
||||
import java.sql.Connection;
|
||||
import java.sql.DriverManager;
|
||||
import java.sql.ResultSet;
|
||||
import java.sql.SQLException;
|
||||
import java.sql.Statement;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
public class CRMReportInterface {
|
||||
|
||||
// JDBC 驱动器名称以及数据库 URL
|
||||
static final String JDBC_DRIVER = "com.microsoft.sqlserver.jdbc.SQLServerDriver";
|
||||
static final String DB_URL = "jdbc:sqlserver://118.142.0.178:1550;databaseName=Hayman_prod";
|
||||
|
||||
// 数据库凭据
|
||||
static final String USER = "user01";
|
||||
static final String PASS = "haySIS-2302";
|
||||
|
||||
public static void main(String[] args) {
|
||||
Connection conn = null;
|
||||
Statement stmt = null;
|
||||
try {
|
||||
// 注册 JDBC 驱动器
|
||||
Class.forName(JDBC_DRIVER);
|
||||
|
||||
// 打开一个连接
|
||||
System.out.println("连接数据库...");
|
||||
conn = DriverManager.getConnection(DB_URL, USER, PASS);
|
||||
|
||||
// 执行查询步骤1: 生成 RW0095 报告以获取客户完整数据
|
||||
System.out.println("执行步骤1:生成 RW0095 报告...");
|
||||
// 执行相应的查询并获取数据
|
||||
// List<CustomerData> customerData = retrieveCustomerData();
|
||||
// 执行查询步骤2: 使用 MZG013 报告检查客户的销售历史
|
||||
System.out.println("执行步骤2:使用 MZG013 报告检查客户的销售历史...");
|
||||
// 执行相应的查询并获取数据
|
||||
List<TransactionData> transactionData = retrieveTransactionData();
|
||||
List<String> collect = transactionData.stream().map(TransactionData::getUserMember).collect(Collectors.toList());
|
||||
List<CustomerData> customerData = retrieveCustomerData(collect);
|
||||
for (TransactionData transactionDatum : transactionData) {
|
||||
for (CustomerData customerDatum : customerData) {
|
||||
if (customerDatum.getMbrCode().equals(transactionDatum.getUserMember())) {
|
||||
customerDatum.setLastMonth(transactionDatum.getSumAmt());
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
// 执行步骤3: 合并(vlookup)RW0095中的客户购买金额
|
||||
System.out.println("执行步骤3:合并客户购买金额...");
|
||||
// 执行相应的操作,如vlookup
|
||||
|
||||
// 执行步骤4: 按“发行店”筛选以分离不同文件并逐个发送给店铺
|
||||
System.out.println("执行步骤4:按发行店筛选并发送文件给店铺...");
|
||||
// 执行相应的操作,如过滤和导出
|
||||
String filePath = "C:\\Users\\10233\\Desktop\\CRM.csv";
|
||||
exportToCSV(customerData, filePath);
|
||||
// 关闭连接
|
||||
conn.close();
|
||||
} catch (SQLException se) {
|
||||
// 处理 JDBC 错误
|
||||
se.printStackTrace();
|
||||
} catch (Exception e) {
|
||||
// 处理 Class.forName 错误
|
||||
e.printStackTrace();
|
||||
} finally {
|
||||
// 关闭资源
|
||||
try {
|
||||
if (stmt != null) stmt.close();
|
||||
} catch (SQLException se2) {
|
||||
} // 什么都不做
|
||||
try {
|
||||
if (conn != null) conn.close();
|
||||
} catch (SQLException se) {
|
||||
se.printStackTrace();
|
||||
}
|
||||
}
|
||||
System.out.println("接口执行完成!");
|
||||
}
|
||||
|
||||
private static void exportToCSV(List<CustomerData> customerDataList, String filePath) throws IOException {
|
||||
FileWriter writer = new FileWriter(filePath);
|
||||
|
||||
// // 写入 CSV 文件的第一行,即字段名
|
||||
// writer.append("User Member,Mbr Name,Sh Code,Sum Amt\n");
|
||||
//
|
||||
// // 遍历数据列表,并将每一行数据写入 CSV 文件
|
||||
// for (TransactionData transaction : transactionDataList) {
|
||||
// writer.append(transaction.getUserMember()).append(",");
|
||||
// writer.append(transaction.getMbrName()).append(",");
|
||||
// writer.append(transaction.getShCode()).append(",");
|
||||
// writer.append(String.valueOf(transaction.getSumAmt())).append("\n");
|
||||
// }
|
||||
writer.append("mbrCode,mbrName,mbrMobile,mbrGroup,mbrStatus,joinDate,mbrIssue,birthMonth,mbrSex,offBonus,effBonus,sumBonus,lastMonth\n");
|
||||
|
||||
// 遍历 customerDataList,并将数据写入 CSV 文件
|
||||
for (CustomerData customer : customerDataList) {
|
||||
writer.append(customer.getMbrCode()).append(",");
|
||||
writer.append(customer.getMbrName()).append(",");
|
||||
writer.append(customer.getMbrMobile()).append(",");
|
||||
writer.append(customer.getMbrGroup()).append(",");
|
||||
writer.append(customer.getMbrStatus()).append(",");
|
||||
writer.append(customer.getJoinDate().toString()).append(","); // 日期需要根据实际情况格式化
|
||||
writer.append(customer.getMbrIssue()).append(",");
|
||||
writer.append(Integer.toString(customer.getBirthMonth())).append(",");
|
||||
writer.append(customer.getMbrSex()).append(",");
|
||||
writer.append(Double.toString(customer.getOffBonus())).append(",");
|
||||
writer.append(Double.toString(customer.getEffBonus())).append(",");
|
||||
writer.append(Double.toString(customer.getSumBonus())).append(",");
|
||||
writer.append(Double.toString(customer.getLastMonth())).append("\n");
|
||||
}
|
||||
|
||||
writer.close();
|
||||
}
|
||||
|
||||
public static List<CustomerData> retrieveCustomerData(List<String> collect) {
|
||||
List<CustomerData> customerDataList = new ArrayList<>();
|
||||
Connection conn = null;
|
||||
Statement stmt = null;
|
||||
try {
|
||||
// 注册 JDBC 驱动器
|
||||
Class.forName(JDBC_DRIVER);
|
||||
|
||||
// 打开一个连接
|
||||
System.out.println("连接数据库...");
|
||||
conn = DriverManager.getConnection(DB_URL, USER, PASS);
|
||||
|
||||
// 执行查询
|
||||
System.out.println("创建声明...");
|
||||
stmt = conn.createStatement();
|
||||
String sql;
|
||||
// 构建 IN 子句的字符串,用于添加到 SQL 查询中
|
||||
StringBuilder inClause = new StringBuilder("(");
|
||||
for (String code : collect) {
|
||||
inClause.append("'").append(code).append("',");
|
||||
}
|
||||
inClause.deleteCharAt(inClause.length() - 1); // 删除最后一个逗号
|
||||
inClause.append(")");
|
||||
|
||||
// 构建完整的 SQL 查询语句
|
||||
sql = "SELECT * FROM V_RW0095B WHERE mbr_code IN " + inClause.toString();
|
||||
ResultSet rs = stmt.executeQuery(sql);
|
||||
|
||||
|
||||
// 处理结果集
|
||||
while (rs.next()) {
|
||||
// 将每行数据转换为 CustomerData 对象并添加到列表中
|
||||
CustomerData customer = new CustomerData();
|
||||
customer.setMbrCode(rs.getString("mbr_code"));
|
||||
customer.setMbrName(rs.getString("mbr_name"));
|
||||
customer.setMbrMobile(rs.getString("mbr_mobile"));
|
||||
customer.setMbrGroup(rs.getString("mbr_group"));
|
||||
customer.setMbrStatus(rs.getString("mbr_status"));
|
||||
customer.setJoinDate(rs.getDate("join_date"));
|
||||
customer.setMbrIssue(rs.getString("mbr_issue"));
|
||||
customer.setBirthMonth(rs.getInt("birth_m"));
|
||||
customer.setMbrSex(rs.getString("mbr_sex"));
|
||||
customer.setOffBonus(rs.getDouble("off_bonus"));
|
||||
customer.setEffBonus(rs.getDouble("eff_bonus"));
|
||||
customer.setSumBonus(rs.getDouble("sum_bonus"));
|
||||
customerDataList.add(customer);
|
||||
|
||||
}
|
||||
|
||||
// 清理环境
|
||||
rs.close();
|
||||
stmt.close();
|
||||
conn.close();
|
||||
} catch (SQLException se) {
|
||||
// 处理 JDBC 错误
|
||||
se.printStackTrace();
|
||||
} catch (Exception e) {
|
||||
// 处理 Class.forName 错误
|
||||
e.printStackTrace();
|
||||
} finally {
|
||||
// 关闭资源
|
||||
try {
|
||||
if (stmt != null) stmt.close();
|
||||
} catch (SQLException se2) {
|
||||
} // 什么都不做
|
||||
try {
|
||||
if (conn != null) conn.close();
|
||||
} catch (SQLException se) {
|
||||
se.printStackTrace();
|
||||
}
|
||||
}
|
||||
System.out.println("查询执行完成!");
|
||||
return customerDataList;
|
||||
}
|
||||
|
||||
public static List<TransactionData> retrieveTransactionData() {
|
||||
List<TransactionData> transactionDataList = new ArrayList<>();
|
||||
Connection conn = null;
|
||||
Statement stmt = null;
|
||||
try {
|
||||
// 注册 JDBC 驱动器
|
||||
Class.forName(JDBC_DRIVER);
|
||||
|
||||
// 打开一个连接
|
||||
System.out.println("连接数据库...");
|
||||
conn = DriverManager.getConnection(DB_URL, USER, PASS);
|
||||
|
||||
// 执行查询
|
||||
System.out.println("创建声明...");
|
||||
stmt = conn.createStatement();
|
||||
String sql;
|
||||
sql = "SELECT user_member,mbr_name,sum(trx_bas_amt) sumAmtByMebBySh FROM V_MZG013\n" +
|
||||
"WHERE trx_date >= DATEADD(day, -7, GETDATE())\n" +
|
||||
"and user_member is not NULL\n" +
|
||||
"GROUP BY user_member,mbr_name";
|
||||
ResultSet rs = stmt.executeQuery(sql);
|
||||
|
||||
// 处理结果集
|
||||
while (rs.next()) {
|
||||
// 将每行数据转换为 TransactionData 对象并添加到列表中
|
||||
TransactionData transaction = new TransactionData();
|
||||
transaction.setUserMember(rs.getString("user_member"));
|
||||
transaction.setMbrName(rs.getString("mbr_name"));
|
||||
// transaction.setShCode(rs.getString("sh_code"));
|
||||
transaction.setSumAmt(rs.getDouble("sumAmtByMebBySh"));
|
||||
// transaction.setTrxNo(rs.getString("trx_no"));
|
||||
// transaction.setTrxDate(rs.getTimestamp("trx_date"));
|
||||
// transaction.setTrxType(rs.getString("trx_type"));
|
||||
// transaction.setTrxStatus(rs.getString("trx_status"));
|
||||
// transaction.setTrxTotQty(rs.getDouble("trx_tot_qty"));
|
||||
// transaction.setCurrCode(rs.getString("curr_code"));
|
||||
// transaction.setExchRate(rs.getDouble("exch_rate"));
|
||||
// transaction.setDiscountPerc(rs.getDouble("discount_perc"));
|
||||
// transaction.setTrxAccAmt(rs.getDouble("trx_acc_amt"));
|
||||
// transaction.setTrxBasAmt(rs.getDouble("trx_bas_amt"));
|
||||
// transaction.setOutstandAmt(rs.getDouble("outstand_amt"));
|
||||
// transaction.setReceiveAmt(rs.getDouble("receive_amt"));
|
||||
// transaction.setChangeAmt(rs.getDouble("change_amt"));
|
||||
// transaction.setTrxTotBonus(rs.getDouble("trx_tot_bonus"));
|
||||
// transaction.setDepositNo(rs.getString("deposit_no"));
|
||||
// transaction.setDepositAmt(rs.getDouble("deposit_amt"));
|
||||
// transaction.setDepositStatus(rs.getString("deposit_status"));
|
||||
// transaction.setTrxAmtDesc(rs.getString("trx_amt_desc"));
|
||||
// transaction.setRemark(rs.getString("remark"));
|
||||
// transaction.setShCode(rs.getString("sh_code"));
|
||||
// transaction.setWhCodeFrom(rs.getString("wh_code_from"));
|
||||
// transaction.setWhCodeTo(rs.getString("wh_code_to"));
|
||||
// transaction.setIssuedBy(rs.getString("issued_by"));
|
||||
// transaction.setClientCode(rs.getString("client_code"));
|
||||
// transaction.setClientName(rs.getString("client_name"));
|
||||
// transaction.setSalesmanCode(rs.getString("salesman_code"));
|
||||
// transaction.setCtypeCode(rs.getString("ctype_code"));
|
||||
// transaction.setUpdatedOn(rs.getTimestamp("updated_on"));
|
||||
// transaction.setDocType(rs.getString("doc_type"));
|
||||
// transaction.setRefNo(rs.getString("ref_no"));
|
||||
// transaction.setAdjType(rs.getString("adj_type"));
|
||||
// transaction.setRefType(rs.getString("ref_type"));
|
||||
// transaction.setOrderNo(rs.getString("order_no"));
|
||||
// transaction.setRecoverF(rs.getString("recover_f"));
|
||||
// transaction.setRecoverT(rs.getString("recover_t"));
|
||||
// transaction.setRequestBy(rs.getString("request_by"));
|
||||
// transaction.setError(rs.getString("error"));
|
||||
// transaction.setAuthorizedDate(rs.getTimestamp("authorized_date"));
|
||||
// transaction.setAuthorizedBy(rs.getString("authorized_by"));
|
||||
// transaction.setChangeCurrCode(rs.getString("change_curr_code"));
|
||||
// transaction.setChgRate(rs.getDouble("chg_rate"));
|
||||
// transaction.setCashier(rs.getString("cashier"));
|
||||
// transaction.setCashiNo(rs.getString("cashi_no"));
|
||||
// transaction.setSalesmanCode2(rs.getString("salesman_code2"));
|
||||
// transaction.setClassId(rs.getString("class_id"));
|
||||
// transaction.setDisAmt(rs.getDouble("dis_amt"));
|
||||
// transaction.setAcStatus(rs.getString("ac_status"));
|
||||
// transaction.setReprint(rs.getString("reprint"));
|
||||
// transaction.setAlt1(rs.getString("alt_1"));
|
||||
// transaction.setAlt2(rs.getString("alt_2"));
|
||||
// transaction.setAlt3(rs.getString("alt_3"));
|
||||
// transaction.setAlt4(rs.getString("alt_4"));
|
||||
// transaction.setAlt5(rs.getString("alt_5"));
|
||||
// transaction.setAltD1(rs.getDate("alt_d1"));
|
||||
// transaction.setAltD2(rs.getDate("alt_d2"));
|
||||
// transaction.setAltD3(rs.getDate("alt_d3"));
|
||||
// transaction.setAltD4(rs.getDate("alt_d4"));
|
||||
// transaction.setAltD5(rs.getDate("alt_d5"));
|
||||
// transaction.setSalesmanCode3(rs.getString("salesman_code3"));
|
||||
// transaction.setContractNo(rs.getString("contract_no"));
|
||||
// transaction.setExpireDate(rs.getTimestamp("expire_date"));
|
||||
// transaction.setDepositNetAmt(rs.getDouble("deposit_netamt"));
|
||||
// transaction.setClientRestriction(rs.getString("client_restriction"));
|
||||
// transaction.setRefStatus(rs.getString("ref_status"));
|
||||
// transaction.setMbrDis(rs.getDouble("mbr_dis"));
|
||||
// transaction.setPmtDiscount(rs.getDouble("pmt_discount"));
|
||||
// transaction.setPmtAmount(rs.getDouble("pmt_amount"));
|
||||
// transaction.setPmtNo(rs.getString("pmt_no"));
|
||||
// transaction.setRefCode(rs.getString("ref_code"));
|
||||
// transaction.setDocApproved(rs.getString("doc_approved"));
|
||||
// transaction.setRefractionNo(rs.getString("refraction_no"));
|
||||
// transaction.setCcpTot(rs.getDouble("ccp_tot"));
|
||||
// transaction.setCcpRed(rs.getDouble("ccp_red"));
|
||||
// transaction.setCcpExpired(rs.getDouble("ccp_expired"));
|
||||
// transaction.setPrintedTimes(rs.getInt("printed_times"));
|
||||
// transaction.setPickupShop(rs.getString("pickup_shop"));
|
||||
// transaction.setDeliveryDate(rs.getDate("delivery_date"));
|
||||
// transaction.setDeliveryTime(rs.getString("delivery_time"));
|
||||
// transaction.setWsCode(rs.getString("ws_code"));
|
||||
// transaction.setClCode(rs.getString("cl_code"));
|
||||
// transaction.setClDesc(rs.getString("cl_desc"));
|
||||
// transaction.setRatio(rs.getString("ratio"));
|
||||
// transaction.setUserMember(rs.getString("user_member"));
|
||||
// transaction.setHflag(rs.getString("hflag"));
|
||||
// transaction.setIssueShop(rs.getString("issue_shop"));
|
||||
// transaction.setHoUpdBy(rs.getString("ho_upd_by"));
|
||||
// transaction.setHoUpdOn(rs.getTimestamp("ho_upd_on"));
|
||||
// transaction.setBonusExpired(rs.getDouble("bonus_expired"));
|
||||
// transaction.setBonusRed(rs.getDouble("bonus_red"));
|
||||
// transaction.setConfirmedOn(rs.getTimestamp("confirmed_on"));
|
||||
// transaction.setConfirmedBy(rs.getString("confirmed_by"));
|
||||
// transaction.setDocConfirmed(rs.getString("doc_confirmed"));
|
||||
// transaction.setBrNo(rs.getString("br_no"));
|
||||
// transaction.setChangeAmt2(rs.getDouble("change_amt2"));
|
||||
// transaction.setSalesDate(rs.getDate("sales_date"));
|
||||
// transaction.setMbrName(rs.getString("mbr_name"));
|
||||
// transaction.setCanEntryDis(rs.getString("can_entry_dis"));
|
||||
// transaction.setReactiveClient(rs.getString("reactive_client"));
|
||||
// transaction.setReactiveMbr(rs.getString("reactive_mbr"));
|
||||
// transaction.setShUpdBy(rs.getString("sh_upd_by"));
|
||||
// transaction.setShUpdOn(rs.getTimestamp("sh_upd_on"));
|
||||
// transaction.setTax1(rs.getDouble("tax1"));
|
||||
// transaction.setTax2(rs.getDouble("tax2"));
|
||||
// transaction.setTax3(rs.getDouble("tax3"));
|
||||
// transaction.setTax4(rs.getDouble("tax4"));
|
||||
// transaction.setTax5(rs.getDouble("tax5"));
|
||||
// transaction.setAltChar1(rs.getString("alt_char1"));
|
||||
// transaction.setAltChar2(rs.getString("alt_char2"));
|
||||
// transaction.setAltChar3(rs.getString("alt_char3"));
|
||||
// transaction.setAltChar4(rs.getString("alt_char4"));
|
||||
// transaction.setAltChar5(rs.getString("alt_char5"));
|
||||
// transaction.setAltNum1(rs.getDouble("alt_num1"));
|
||||
// transaction.setAltNum2(rs.getDouble("alt_num2"));
|
||||
// transaction.setAltNum3(rs.getDouble("alt_num3"));
|
||||
// transaction.setAltNum4(rs.getDouble("alt_num4"));
|
||||
// transaction.setAltNum5(rs.getDouble("alt_num5"));
|
||||
// transaction.setNewClient(rs.getString("new_client"));
|
||||
// transaction.setNewMbr(rs.getString("new_mbr"));
|
||||
// transaction.setPmtExtraDiscount(rs.getDouble("pmt_extra_discount"));
|
||||
// transaction.setPmtExtraAmount(rs.getDouble("pmt_extra_amount"));
|
||||
// transaction.setManualDiscount(rs.getDouble("manual_discount"));
|
||||
// transaction.setManualAmount(rs.getDouble("manual_amount"));
|
||||
// transaction.setUsermbrDiscount(rs.getDouble("usermbr_discount"));
|
||||
// transaction.setClientDiscount(rs.getDouble("client_discount"));
|
||||
// transaction.setHoldVoid(rs.getString("hold_void"));
|
||||
// transaction.setPayBasAmt(rs.getDouble("pay_bas_amt"));
|
||||
// transaction.setPayDesc(rs.getString("pay_desc"));
|
||||
// transaction.setPayCode(rs.getString("pay_code"));
|
||||
// transaction.setCardNo(rs.getString("card_no"));
|
||||
// transaction.setPayCurr(rs.getString("pay_curr"));
|
||||
// transaction.setPayCurrAmt(rs.getDouble("pay_curr_amt"));
|
||||
// transaction.setOnbehalfPaid(rs.getString("onbehalf_paid"));
|
||||
// transaction.setOnbehalfLoc(rs.getString("onbehalf_loc"));
|
||||
// transaction.setOldCardNo(rs.getString("old_card_no"));
|
||||
// transaction.setTrxYear(rs.getInt("TRX_YEAR"));
|
||||
// transaction.setTrxMonth(rs.getInt("TRX_MONTH"));
|
||||
|
||||
transactionDataList.add(transaction);
|
||||
}
|
||||
|
||||
|
||||
// 清理环境
|
||||
rs.close();
|
||||
stmt.close();
|
||||
conn.close();
|
||||
} catch (SQLException | ClassNotFoundException e) {
|
||||
// 处理异常
|
||||
e.printStackTrace();
|
||||
}
|
||||
System.out.println("查询执行完成!");
|
||||
return transactionDataList;
|
||||
}
|
||||
|
||||
// 示例:导出数据到CSV文件
|
||||
private static void exportToCSV(ResultSet resultSet, String filePath) throws SQLException, IOException {
|
||||
FileWriter writer = new FileWriter(filePath);
|
||||
|
||||
while (resultSet.next()) {
|
||||
// 将结果写入CSV文件
|
||||
// 这里需要根据实际情况将数据写入CSV文件
|
||||
}
|
||||
|
||||
writer.close();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -20,25 +20,26 @@ public class FileProperties {
|
||||
|
||||
private String linuxDomain;
|
||||
|
||||
public ElPath getSys(){
|
||||
public ElPath getSys() {
|
||||
String os = System.getProperty("os.name");
|
||||
if(os.toLowerCase().startsWith("win")) {
|
||||
if (os.toLowerCase().startsWith("win")) {
|
||||
return windows;
|
||||
} else if(os.toLowerCase().startsWith("mac")){
|
||||
} else if (os.toLowerCase().startsWith("mac")) {
|
||||
return mac;
|
||||
}
|
||||
return linux;
|
||||
}
|
||||
public String getLinuxDomain(){
|
||||
|
||||
public String getLinuxDomain() {
|
||||
String os = System.getProperty("os.name");
|
||||
if((!os.toLowerCase().startsWith("win") )&& (!os.toLowerCase().startsWith("mac"))) {
|
||||
if ((!os.toLowerCase().startsWith("win")) && (!os.toLowerCase().startsWith("mac"))) {
|
||||
return linuxDomain;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Data
|
||||
public static class ElPath{
|
||||
public static class ElPath {
|
||||
private String path;
|
||||
}
|
||||
}
|
||||
|
||||
34
src/main/java/com/ai/da/common/config/MinIoClientConfig.java
Normal file
34
src/main/java/com/ai/da/common/config/MinIoClientConfig.java
Normal file
@@ -0,0 +1,34 @@
|
||||
package com.ai.da.common.config;
|
||||
|
||||
import io.minio.MinioClient;
|
||||
import lombok.Data;
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
@Data
|
||||
@Component
|
||||
public class MinIoClientConfig {
|
||||
@Value("${minio.endpoint}")
|
||||
private String endpoint;
|
||||
@Value("${minio.accessKey}")
|
||||
private String accessKey;
|
||||
@Value("${minio.secretKey}")
|
||||
private String secretKey;
|
||||
|
||||
/**
|
||||
* 注入minio 客户端
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
@Bean
|
||||
public MinioClient minioClient() {
|
||||
|
||||
return MinioClient.builder()
|
||||
.endpoint(endpoint)
|
||||
.credentials(accessKey, secretKey)
|
||||
.build();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
1831
src/main/java/com/ai/da/common/config/MyTaskScheduler.java
Normal file
1831
src/main/java/com/ai/da/common/config/MyTaskScheduler.java
Normal file
File diff suppressed because it is too large
Load Diff
@@ -1,20 +1,26 @@
|
||||
package com.ai.da.common.config.mybatis.plus;
|
||||
|
||||
import com.baomidou.mybatisplus.annotation.DbType;
|
||||
import com.baomidou.mybatisplus.extension.plugins.MybatisPlusInterceptor;
|
||||
import com.baomidou.mybatisplus.extension.plugins.inner.PaginationInnerInterceptor;
|
||||
import org.mybatis.spring.annotation.MapperScan;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
|
||||
@Configuration
|
||||
@MapperScan("com.ai.da.mapper")
|
||||
public class MybatisPlusConfig {
|
||||
|
||||
@Bean
|
||||
public MybatisPlusInterceptor mybatisPlusInterceptor() {
|
||||
MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
|
||||
interceptor.addInnerInterceptor(new PaginationInnerInterceptor(DbType.MYSQL));
|
||||
return interceptor;
|
||||
}
|
||||
}
|
||||
package com.ai.da.common.config;
|
||||
|
||||
import com.baomidou.mybatisplus.annotation.DbType;
|
||||
import com.baomidou.mybatisplus.extension.plugins.MybatisPlusInterceptor;
|
||||
import com.baomidou.mybatisplus.extension.plugins.inner.PaginationInnerInterceptor;
|
||||
import org.mybatis.spring.annotation.MapperScan;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
|
||||
@Configuration
|
||||
public class MybatisPlusConfig {
|
||||
|
||||
@Bean(name = "primaryMybatisPlusInterceptor")
|
||||
public MybatisPlusInterceptor primaryMybatisPlusInterceptor() {
|
||||
MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
|
||||
interceptor.addInnerInterceptor(new PaginationInnerInterceptor(DbType.MYSQL));
|
||||
return interceptor;
|
||||
}
|
||||
|
||||
@Bean(name = "secondaryMybatisPlusInterceptor")
|
||||
public MybatisPlusInterceptor secondaryMybatisPlusInterceptor() {
|
||||
MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
|
||||
interceptor.addInnerInterceptor(new PaginationInnerInterceptor(DbType.MYSQL));
|
||||
return interceptor;
|
||||
}
|
||||
}
|
||||
46
src/main/java/com/ai/da/common/config/PayPalClient.java
Normal file
46
src/main/java/com/ai/da/common/config/PayPalClient.java
Normal file
@@ -0,0 +1,46 @@
|
||||
package com.ai.da.common.config;
|
||||
|
||||
import com.paypal.core.PayPalEnvironment;
|
||||
import com.paypal.core.PayPalHttpClient;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.context.annotation.PropertySource;
|
||||
|
||||
@Configuration
|
||||
@Slf4j
|
||||
@PropertySource("classpath:payment.properties")
|
||||
public class PayPalClient {
|
||||
|
||||
public PayPalHttpClient client(String mode, String clientId, String clientSecret) {
|
||||
log.info("mode={}, clientId={}, clientSecret={}", mode, clientId, clientSecret);
|
||||
PayPalEnvironment environment = mode.equals("live") ? new PayPalEnvironment.Live(clientId, clientSecret) : new PayPalEnvironment.Sandbox(clientId, clientSecret);
|
||||
return new PayPalHttpClient(environment);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param jo
|
||||
* @param pre
|
||||
* @return
|
||||
*/
|
||||
/*public String prettyPrint(JSONObject jo, String pre) {
|
||||
Iterator<?> keys = jo.keys();
|
||||
StringBuilder pretty = new StringBuilder();
|
||||
while (keys.hasNext()) {
|
||||
String key = (String) keys.next();
|
||||
pretty.append(String.format("%s%s: ", pre, StringUtils.capitalize(key)));
|
||||
if (jo.get(key) instanceof JSONObject) {
|
||||
pretty.append(prettyPrint(jo.getJSONObject(key), pre + "\t"));
|
||||
} else if (jo.get(key) instanceof JSONArray) {
|
||||
int sno = 1;
|
||||
for (Object jsonObject : jo.getJSONArray(key)) {
|
||||
pretty.append(String.format("\n%s\t%d:\n", pre, sno++));
|
||||
pretty.append(prettyPrint((JSONObject) jsonObject, pre + "\t\t"));
|
||||
}
|
||||
} else {
|
||||
pretty.append(String.format("%s\n", jo.getString(key)));
|
||||
}
|
||||
}
|
||||
return pretty.toString();
|
||||
}*/
|
||||
}
|
||||
|
||||
@@ -0,0 +1,63 @@
|
||||
package com.ai.da.common.config;
|
||||
|
||||
import com.baomidou.mybatisplus.autoconfigure.MybatisPlusProperties;
|
||||
import com.baomidou.mybatisplus.core.config.GlobalConfig;
|
||||
import com.baomidou.mybatisplus.extension.plugins.MybatisPlusInterceptor;
|
||||
import com.baomidou.mybatisplus.extension.spring.MybatisSqlSessionFactoryBean;
|
||||
import org.apache.ibatis.session.SqlSessionFactory;
|
||||
import org.mybatis.spring.SqlSessionFactoryBean;
|
||||
import org.mybatis.spring.SqlSessionTemplate;
|
||||
import org.mybatis.spring.annotation.MapperScan;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.beans.factory.annotation.Qualifier;
|
||||
import org.springframework.boot.context.properties.ConfigurationProperties;
|
||||
import org.springframework.boot.jdbc.DataSourceBuilder;
|
||||
import org.springframework.context.ApplicationContext;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.context.annotation.Primary;
|
||||
|
||||
import javax.sql.DataSource;
|
||||
|
||||
@Configuration
|
||||
@MapperScan(basePackages = "com.ai.da.mapper.primary", sqlSessionFactoryRef = "primarySqlSessionFactory")
|
||||
public class PrimaryDataSourceConfig {
|
||||
@Autowired
|
||||
private MybatisPlusProperties mybatisPlusProperties;
|
||||
|
||||
@Primary
|
||||
@Bean(name = "primaryDataSource")
|
||||
@ConfigurationProperties(prefix = "spring.datasource.primary")
|
||||
public DataSource dataSource() {
|
||||
return DataSourceBuilder.create().build();
|
||||
}
|
||||
|
||||
@Primary
|
||||
@Bean(name = "primarySqlSessionFactory")
|
||||
public SqlSessionFactory sqlSessionFactory(
|
||||
@Qualifier("primaryDataSource") DataSource dataSource,
|
||||
ApplicationContext applicationContext,
|
||||
@Qualifier("primaryMybatisPlusInterceptor") MybatisPlusInterceptor mybatisPlusInterceptor) throws Exception {
|
||||
MybatisSqlSessionFactoryBean bean = new MybatisSqlSessionFactoryBean();
|
||||
bean.setDataSource(dataSource);
|
||||
bean.setMapperLocations(applicationContext.getResources("classpath:mapper/primary/*.xml"));
|
||||
// 设置 MyBatis Plus 全局配置
|
||||
GlobalConfig globalConfig = this.mybatisPlusProperties.getGlobalConfig();
|
||||
if (globalConfig != null) {
|
||||
bean.setGlobalConfig(globalConfig);
|
||||
}
|
||||
bean.setPlugins(mybatisPlusInterceptor);
|
||||
return bean.getObject();
|
||||
}
|
||||
|
||||
@Primary
|
||||
@Bean(name = "primarySqlSessionTemplate")
|
||||
public SqlSessionTemplate sqlSessionTemplate(
|
||||
@Qualifier("primarySqlSessionFactory") SqlSessionFactory sqlSessionFactory) {
|
||||
return new SqlSessionTemplate(sqlSessionFactory);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
42
src/main/java/com/ai/da/common/config/RedisConfig.java
Normal file
42
src/main/java/com/ai/da/common/config/RedisConfig.java
Normal file
@@ -0,0 +1,42 @@
|
||||
package com.ai.da.common.config;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonAutoDetect;
|
||||
import com.fasterxml.jackson.annotation.JsonTypeInfo;
|
||||
import com.fasterxml.jackson.annotation.PropertyAccessor;
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import com.fasterxml.jackson.databind.jsontype.impl.LaissezFaireSubTypeValidator;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.data.redis.connection.RedisConnectionFactory;
|
||||
import org.springframework.data.redis.core.RedisTemplate;
|
||||
import org.springframework.data.redis.serializer.Jackson2JsonRedisSerializer;
|
||||
import org.springframework.data.redis.serializer.StringRedisSerializer;
|
||||
|
||||
@Configuration
|
||||
public class RedisConfig {
|
||||
@Bean(name = "redisTemplate")
|
||||
public RedisTemplate<String, Object> getRedisTemplate(RedisConnectionFactory factory) {
|
||||
RedisTemplate<String, Object> redisTemplate = new RedisTemplate<>();
|
||||
redisTemplate.setConnectionFactory(factory);
|
||||
|
||||
StringRedisSerializer stringRedisSerializer = new StringRedisSerializer();
|
||||
|
||||
redisTemplate.setKeySerializer(stringRedisSerializer); // key的序列化类型
|
||||
|
||||
Jackson2JsonRedisSerializer jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer(Object.class);
|
||||
ObjectMapper objectMapper = new ObjectMapper();
|
||||
objectMapper.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
|
||||
// 方法过期,改为下面代码
|
||||
// objectMapper.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);
|
||||
objectMapper.activateDefaultTyping(LaissezFaireSubTypeValidator.instance,
|
||||
ObjectMapper.DefaultTyping.NON_FINAL, JsonTypeInfo.As.PROPERTY);
|
||||
jackson2JsonRedisSerializer.setObjectMapper(objectMapper);
|
||||
jackson2JsonRedisSerializer.setObjectMapper(objectMapper);
|
||||
|
||||
redisTemplate.setValueSerializer(jackson2JsonRedisSerializer); // value的序列化类型
|
||||
redisTemplate.setHashKeySerializer(stringRedisSerializer);
|
||||
redisTemplate.setHashValueSerializer(jackson2JsonRedisSerializer);
|
||||
redisTemplate.afterPropertiesSet();
|
||||
return redisTemplate;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,49 @@
|
||||
package com.ai.da.common.config;
|
||||
|
||||
import com.baomidou.mybatisplus.extension.plugins.MybatisPlusInterceptor;
|
||||
import com.baomidou.mybatisplus.extension.spring.MybatisSqlSessionFactoryBean;
|
||||
import org.apache.ibatis.session.SqlSessionFactory;
|
||||
import org.mybatis.spring.SqlSessionFactoryBean;
|
||||
import org.mybatis.spring.SqlSessionTemplate;
|
||||
import org.mybatis.spring.annotation.MapperScan;
|
||||
import org.springframework.beans.factory.annotation.Qualifier;
|
||||
import org.springframework.boot.context.properties.ConfigurationProperties;
|
||||
import org.springframework.boot.jdbc.DataSourceBuilder;
|
||||
import org.springframework.context.ApplicationContext;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
|
||||
import javax.sql.DataSource;
|
||||
|
||||
@Configuration
|
||||
@MapperScan(basePackages = "com.ai.da.mapper.secondary", sqlSessionFactoryRef = "secondarySqlSessionFactory")
|
||||
public class SecondaryDataSourceConfig {
|
||||
|
||||
@Bean(name = "secondaryDataSource")
|
||||
@ConfigurationProperties(prefix = "spring.datasource.secondary")
|
||||
public DataSource dataSource() {
|
||||
return DataSourceBuilder.create().build();
|
||||
}
|
||||
|
||||
@Bean(name = "secondarySqlSessionFactory")
|
||||
public SqlSessionFactory sqlSessionFactory(
|
||||
@Qualifier("secondaryDataSource") DataSource dataSource,
|
||||
ApplicationContext applicationContext,
|
||||
@Qualifier("secondaryMybatisPlusInterceptor") MybatisPlusInterceptor mybatisPlusInterceptor) throws Exception {
|
||||
MybatisSqlSessionFactoryBean bean = new MybatisSqlSessionFactoryBean();
|
||||
// SqlSessionFactoryBean bean = new SqlSessionFactoryBean();
|
||||
bean.setDataSource(dataSource);
|
||||
bean.setMapperLocations(applicationContext.getResources("classpath:mapper/secondary/*.xml"));
|
||||
bean.setPlugins(mybatisPlusInterceptor);
|
||||
return bean.getObject();
|
||||
}
|
||||
|
||||
@Bean(name = "secondarySqlSessionTemplate")
|
||||
public SqlSessionTemplate sqlSessionTemplate(
|
||||
@Qualifier("secondarySqlSessionFactory") SqlSessionFactory sqlSessionFactory) {
|
||||
return new SqlSessionTemplate(sqlSessionFactory);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
260
src/main/java/com/ai/da/common/config/ThreeDSave.java
Normal file
260
src/main/java/com/ai/da/common/config/ThreeDSave.java
Normal file
@@ -0,0 +1,260 @@
|
||||
package com.ai.da.common.config;
|
||||
|
||||
import com.ai.da.common.utils.MinioUtil;
|
||||
import com.ai.da.mapper.primary.ThreeDDetailMapper;
|
||||
import com.ai.da.mapper.primary.ThreeDLayoutMapper;
|
||||
import com.ai.da.mapper.primary.ThreeDPatternLayoutMapper;
|
||||
import com.ai.da.mapper.primary.ThreeDSimpleMapper;
|
||||
import com.ai.da.mapper.primary.entity.ThreeDDetail;
|
||||
import com.ai.da.mapper.primary.entity.ThreeDLayout;
|
||||
import com.ai.da.mapper.primary.entity.ThreeDPatternLayout;
|
||||
import com.ai.da.mapper.primary.entity.ThreeDSimple;
|
||||
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.stereotype.Component;
|
||||
import org.springframework.util.CollectionUtils;
|
||||
|
||||
import jakarta.annotation.PostConstruct;
|
||||
import jakarta.annotation.Resource;
|
||||
import java.io.File;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
@Slf4j
|
||||
@Component
|
||||
public class ThreeDSave {
|
||||
|
||||
@Resource
|
||||
private ThreeDDetailMapper threeDDetailMapper;
|
||||
@Resource
|
||||
private ThreeDSimpleMapper threeDSimpleMapper;
|
||||
@Resource
|
||||
private MinioUtil minioUtil;
|
||||
@Resource
|
||||
private ThreeDLayoutMapper threeDLayoutMapper;
|
||||
@Resource
|
||||
private ThreeDPatternLayoutMapper threeDPatternLayoutMapper;
|
||||
@PostConstruct
|
||||
public void test() {
|
||||
// minioSave();
|
||||
// frontBackDataCreate();
|
||||
// patternDataCreate();
|
||||
}
|
||||
|
||||
private void patternDataCreate() {
|
||||
QueryWrapper<ThreeDSimple> qw = new QueryWrapper<>();
|
||||
qw.lambda().eq(ThreeDSimple::getGender, "female");
|
||||
qw.lambda().ne(ThreeDSimple::getId, 1);
|
||||
List<ThreeDSimple> threeDSimpleList = threeDSimpleMapper.selectList(qw);
|
||||
List<Integer> numbers = new ArrayList<>();
|
||||
String patternPath = "C:\\workspace\\3D\\3D虚拟 1-7\\6.版文件、dxf文件\\女装系列(1)\\女装系列\\56款打版截图";
|
||||
|
||||
File directory = new File(patternPath);
|
||||
|
||||
if (directory.exists() && directory.isDirectory()) {
|
||||
// 获取目录下的所有文件名,并建立编号 -> 文件名的映射
|
||||
Map<Integer, String> fileMap = Arrays.stream(directory.listFiles())
|
||||
.filter(File::isFile) // 只获取文件
|
||||
.map(File::getName) // 获取文件名
|
||||
.collect(Collectors.toMap(
|
||||
name -> {
|
||||
Matcher matcher = Pattern.compile("^\\d+").matcher(name);
|
||||
return matcher.find() ? Integer.parseInt(matcher.group()) : -1;
|
||||
},
|
||||
name -> name,
|
||||
(existing, replacement) -> existing // 处理重复情况,保留原有值
|
||||
));
|
||||
|
||||
for (ThreeDSimple threeDSimple : threeDSimpleList) {
|
||||
String name = threeDSimple.getName();
|
||||
Pattern pattern = Pattern.compile("^\\d+"); // 匹配开头的数字
|
||||
Matcher matcher = pattern.matcher(name);
|
||||
if (matcher.find()) {
|
||||
int number = Integer.parseInt(matcher.group());
|
||||
numbers.add(number);
|
||||
// 匹配对应文件夹,并获取文件
|
||||
if (fileMap.containsKey(number)) {
|
||||
String matchedFolder = fileMap.get(number);
|
||||
File folder = new File(directory, matchedFolder);
|
||||
|
||||
ThreeDPatternLayout threeDPatternLayout = new ThreeDPatternLayout();
|
||||
threeDPatternLayout.setThreeDSimpleId(threeDSimple.getId());
|
||||
threeDPatternLayout.setName(matchedFolder);
|
||||
String minioUrl = "aida-threed/female/pattern-layout/" + matchedFolder;
|
||||
minioUtil.upload(minioUrl, folder);
|
||||
threeDPatternLayout.setUrl(minioUrl);
|
||||
// threeDPatternLayoutMapper.insert(threeDPatternLayout);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
System.out.println("文件编号映射:" + fileMap);
|
||||
}
|
||||
}
|
||||
|
||||
private void frontBackDataCreate() {
|
||||
QueryWrapper<ThreeDSimple> qw = new QueryWrapper<>();
|
||||
qw.lambda().eq(ThreeDSimple::getGender, "female");
|
||||
// qw.lambda().ne(ThreeDSimple::getId, 1);
|
||||
List<ThreeDSimple> threeDSimpleList = threeDSimpleMapper.selectList(qw);
|
||||
List<Integer> numbers = new ArrayList<>();
|
||||
|
||||
// 文件夹名列表
|
||||
String path = "C:\\workspace\\3D\\3D虚拟 1-7\\3D服装真反面整理\\female"; // 目标路径
|
||||
File directory = new File(path);
|
||||
|
||||
if (directory.exists() && directory.isDirectory()) {
|
||||
// 获取文件夹名列表,并建立编号 -> 文件夹名的映射
|
||||
Map<Integer, String> folderMap = Arrays.stream(directory.listFiles())
|
||||
.filter(File::isDirectory)
|
||||
.map(File::getName)
|
||||
.collect(Collectors.toMap(
|
||||
name -> {
|
||||
Matcher matcher = Pattern.compile("^\\d+").matcher(name);
|
||||
return matcher.find() ? Integer.parseInt(matcher.group()) : -1;
|
||||
},
|
||||
name -> name,
|
||||
(existing, replacement) -> existing // 处理重复情况,保留原有值
|
||||
));
|
||||
|
||||
System.out.println("文件夹编号映射:" + folderMap);
|
||||
|
||||
for (ThreeDSimple threeDSimple : threeDSimpleList) {
|
||||
String name = threeDSimple.getName();
|
||||
Pattern pattern = Pattern.compile("^\\d+"); // 匹配开头的数字
|
||||
Matcher matcher = pattern.matcher(name);
|
||||
if (matcher.find()) {
|
||||
int number = Integer.parseInt(matcher.group());
|
||||
numbers.add(number);
|
||||
// 匹配对应文件夹,并获取文件
|
||||
if (folderMap.containsKey(number)) {
|
||||
String matchedFolder = folderMap.get(number);
|
||||
File folder = new File(directory, matchedFolder);
|
||||
if (folder.exists() && folder.isDirectory()) {
|
||||
|
||||
for (File file : folder.listFiles()) {
|
||||
String fileName = file.getName(); // 去掉后缀
|
||||
ThreeDLayout threeDLayout = new ThreeDLayout();
|
||||
threeDLayout.setGender("female");
|
||||
threeDLayout.setThreeDSimpleId(threeDSimple.getId());
|
||||
threeDLayout.setName(file.getName());
|
||||
if (fileName.startsWith("前")) {
|
||||
threeDLayout.setType("front");
|
||||
}else if (fileName.startsWith("后")) {
|
||||
threeDLayout.setType("back");
|
||||
}
|
||||
String minioUrl = "aida-threed/female/layout/" + folderMap.get(number) + " " + file.getName();
|
||||
minioUtil.upload(minioUrl, file);
|
||||
threeDLayout.setUrl(minioUrl);
|
||||
// threeDLayoutMapper.insert(threeDLayout);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
System.out.println(numbers);
|
||||
} else {
|
||||
System.out.println("路径不存在或不是文件夹");
|
||||
}
|
||||
}
|
||||
|
||||
private void minioSave() {
|
||||
// 指定目标文件夹路径
|
||||
String folderPath = "C:\\workspace\\3D\\3D虚拟 1-7\\3D服装整理\\maleZip";
|
||||
|
||||
// 创建文件对象
|
||||
File folder = new File(folderPath);
|
||||
|
||||
// 检查文件夹是否存在且是目录
|
||||
if (folder.exists() && folder.isDirectory()) {
|
||||
// 获取所有 .zip 文件
|
||||
File[] zipFiles = folder.listFiles((dir, name) -> name.toLowerCase().endsWith(".zip"));
|
||||
|
||||
List<String> zipFileNameList = new ArrayList<>();
|
||||
// 输出文件名
|
||||
if (zipFiles != null) {
|
||||
for (File file : zipFiles) {
|
||||
String zipFileName = file.getName();
|
||||
String[] split = zipFileName.split("_");
|
||||
String zipName = split[0];
|
||||
String sizeWithSuffix = split[1];
|
||||
String[] sizeWithSuffixSplit = sizeWithSuffix.split("\\.");
|
||||
String size = sizeWithSuffixSplit[0];
|
||||
// 找到第一个字母的位置
|
||||
int index = 0;
|
||||
while (index < size.length() && Character.UnicodeBlock.of(size.charAt(index)) == Character.UnicodeBlock.CJK_UNIFIED_IDEOGRAPHS) {
|
||||
index++;
|
||||
}
|
||||
|
||||
if (index > 0 && index < size.length()) {
|
||||
String prefix = size.substring(0, index); // "亚码"
|
||||
String suffix = size.substring(index); // "L"
|
||||
|
||||
ThreeDDetail threeDDetail = new ThreeDDetail();
|
||||
threeDDetail.setName(zipFileName);
|
||||
String url = "aida-threed/male/zip/" + zipFileName;
|
||||
threeDDetail.setGender("male");
|
||||
threeDDetail.setSizeType(prefix);
|
||||
threeDDetail.setSize(suffix);
|
||||
threeDDetail.setUrl(url);
|
||||
// threeDDetailMapper.insert(threeDDetail);
|
||||
minioUtil.upload(url, file);
|
||||
|
||||
QueryWrapper<ThreeDSimple> qw = new QueryWrapper<>();
|
||||
qw.lambda().eq(ThreeDSimple::getName, zipName);
|
||||
qw.lambda().eq(ThreeDSimple::getGender, "male");
|
||||
List<ThreeDSimple> threeDSimples = threeDSimpleMapper.selectList(qw);
|
||||
|
||||
if (CollectionUtils.isEmpty(threeDSimples)) {
|
||||
ThreeDSimple threeDSimple = new ThreeDSimple();
|
||||
threeDSimple.setName(zipName);
|
||||
threeDSimple.setGender("male");
|
||||
|
||||
String glbPath = "C:\\workspace\\3D\\3D虚拟 1-7\\3D服装整理\\male\\" + zipName + "\\" +"亚码L";
|
||||
File glbFolder = new File(glbPath);
|
||||
|
||||
// 查找 .glb 文件
|
||||
if (glbFolder.exists() && glbFolder.isDirectory()) {
|
||||
File[] glbFiles = glbFolder.listFiles((dir, name) -> name.toLowerCase().endsWith(".glb"));
|
||||
if (glbFiles != null && glbFiles.length > 0) {
|
||||
for (File glbFile : glbFiles) {
|
||||
String name = glbFile.getName();
|
||||
String glbUrl = "aida-threed/male/glb/" + name;
|
||||
threeDSimple.setUrl(glbUrl);
|
||||
minioUtil.upload(glbUrl, glbFile);
|
||||
}
|
||||
} else {
|
||||
System.out.println("未找到 GLB 文件。" + glbFolder);
|
||||
}
|
||||
} else {
|
||||
System.out.println("GLB 文件夹不存在: " + glbPath);
|
||||
}
|
||||
// threeDSimpleMapper.insert(threeDSimple);
|
||||
threeDDetail.setThreeDSimpleId(threeDSimple.getId());
|
||||
threeDDetailMapper.updateById(threeDDetail);
|
||||
}else {
|
||||
Long id = threeDSimples.get(0).getId();
|
||||
threeDDetail.setThreeDSimpleId(id);
|
||||
threeDDetailMapper.updateById(threeDDetail);
|
||||
}
|
||||
|
||||
} else {
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
} else {
|
||||
System.out.println("未找到 ZIP 文件。");
|
||||
}
|
||||
log.info("aaa");
|
||||
} else {
|
||||
System.out.println("文件夹不存在或不是一个目录。");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,33 +1,42 @@
|
||||
package com.ai.da.common.config;
|
||||
|
||||
|
||||
import org.hibernate.validator.HibernateValidator;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.validation.beanvalidation.MethodValidationPostProcessor;
|
||||
|
||||
import javax.validation.Validation;
|
||||
import javax.validation.Validator;
|
||||
import javax.validation.ValidatorFactory;
|
||||
|
||||
@Configuration
|
||||
public class WebConfig {
|
||||
|
||||
@Bean
|
||||
public Validator validator() {
|
||||
ValidatorFactory validatorFactory = Validation.byProvider(HibernateValidator.class)
|
||||
.configure()
|
||||
//failFast为true出现校验失败的情况,立即结束校验,不再进行后续的校验
|
||||
.failFast(true)
|
||||
.buildValidatorFactory();
|
||||
|
||||
return validatorFactory.getValidator();
|
||||
}
|
||||
|
||||
@Bean
|
||||
public MethodValidationPostProcessor methodValidationPostProcessor() {
|
||||
MethodValidationPostProcessor methodValidationPostProcessor = new MethodValidationPostProcessor();
|
||||
methodValidationPostProcessor.setValidator(validator());
|
||||
return methodValidationPostProcessor;
|
||||
}
|
||||
}
|
||||
package com.ai.da.common.config;
|
||||
|
||||
|
||||
import org.hibernate.validator.HibernateValidator;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.validation.beanvalidation.MethodValidationPostProcessor;
|
||||
import org.springframework.web.servlet.config.annotation.CorsRegistry;
|
||||
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
|
||||
|
||||
import jakarta.validation.Validation;
|
||||
import jakarta.validation.Validator;
|
||||
import jakarta.validation.ValidatorFactory;
|
||||
|
||||
@Configuration
|
||||
public class WebConfig implements WebMvcConfigurer {
|
||||
|
||||
static final String ORIGINS[] = new String[]{"GET", "POST", "PUT", "DELETE"};
|
||||
|
||||
@Override
|
||||
public void addCorsMappings(CorsRegistry registry) {
|
||||
registry.addMapping("/**").allowedOriginPatterns("*").allowCredentials(true).allowedMethods(ORIGINS).maxAge(3600);
|
||||
}
|
||||
|
||||
@Bean
|
||||
public Validator validator() {
|
||||
ValidatorFactory validatorFactory = Validation.byProvider(HibernateValidator.class)
|
||||
.configure()
|
||||
//failFast为true出现校验失败的情况,立即结束校验,不再进行后续的校验
|
||||
.failFast(true)
|
||||
.buildValidatorFactory();
|
||||
|
||||
return validatorFactory.getValidator();
|
||||
}
|
||||
|
||||
@Bean
|
||||
public MethodValidationPostProcessor methodValidationPostProcessor() {
|
||||
MethodValidationPostProcessor methodValidationPostProcessor = new MethodValidationPostProcessor();
|
||||
methodValidationPostProcessor.setValidator(validator());
|
||||
return methodValidationPostProcessor;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,7 +1,19 @@
|
||||
package com.ai.da.common.config.exception;
|
||||
|
||||
import com.ai.da.common.context.UserContext;
|
||||
import com.ai.da.common.response.ResultEnum;
|
||||
import com.ai.da.model.enums.Language;
|
||||
import com.ai.da.model.vo.AuthPrincipalVo;
|
||||
import lombok.Data;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
|
||||
import java.io.InputStream;
|
||||
import java.io.InputStreamReader;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.Locale;
|
||||
import java.util.Objects;
|
||||
import java.util.PropertyResourceBundle;
|
||||
import java.util.ResourceBundle;
|
||||
|
||||
/**
|
||||
* @author: dangweijian
|
||||
@@ -9,20 +21,55 @@ import lombok.Data;
|
||||
* @create: 2020-01-01 17:24
|
||||
**/
|
||||
@Data
|
||||
@Slf4j
|
||||
public class BusinessException extends RuntimeException {
|
||||
|
||||
private Integer code;
|
||||
private String msg;
|
||||
|
||||
public BusinessException(ResultEnum resultEnum){
|
||||
super(resultEnum.getMsg());
|
||||
public BusinessException(ResultEnum resultEnum) {
|
||||
this.code = resultEnum.getCode();
|
||||
this.msg = resultEnum.getMsg();
|
||||
this.msg = getMessageFromResource(resultEnum.getMsg(), getUserLocale());
|
||||
}
|
||||
|
||||
public BusinessException(String msg) {
|
||||
super(msg);
|
||||
this.code = ResultEnum.FAIL.getCode();
|
||||
this.msg = msg;
|
||||
this.msg = getMessageFromResource(msg, getUserLocale());
|
||||
}
|
||||
}
|
||||
|
||||
public BusinessException(String msg, Integer code) {
|
||||
this.code = code;
|
||||
this.msg = getMessageFromResource(msg, getUserLocale());
|
||||
}
|
||||
|
||||
public BusinessException(Throwable cause) {
|
||||
this.code = ResultEnum.FAIL.getCode();
|
||||
this.msg = getMessageFromResource(cause.getMessage(), getUserLocale());
|
||||
}
|
||||
|
||||
private static Locale getUserLocale() {
|
||||
AuthPrincipalVo userInfo = UserContext.getUserHolder();
|
||||
if (Objects.isNull(userInfo)) {
|
||||
return new Locale("en");
|
||||
}
|
||||
return new Locale(Language.valueOf(userInfo.getLanguage()).getValue());
|
||||
}
|
||||
|
||||
public static String getMessageFromResource(String msg) {
|
||||
return getMessageFromResource(msg, getUserLocale());
|
||||
}
|
||||
|
||||
public static String getMessageFromResource(String msg, Locale userLocale) {
|
||||
try (InputStream inputStream = BusinessException.class.getClassLoader().getResourceAsStream("messages_" + userLocale.getLanguage() + ".properties")) {
|
||||
if (inputStream != null) {
|
||||
ResourceBundle bundle = new PropertyResourceBundle(new InputStreamReader(inputStream, StandardCharsets.UTF_8));
|
||||
if (bundle.containsKey(msg)) {
|
||||
return bundle.getString(msg);
|
||||
}
|
||||
}
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
return msg; // 如果找不到对应的资源文件,返回原始的消息
|
||||
}
|
||||
}
|
||||
@@ -51,11 +51,12 @@ public class ExceptionCatch {
|
||||
return Response.error(resultEnum.getCode(), resultEnum.getMsg());
|
||||
}
|
||||
}
|
||||
return Response.error(ResultEnum.ERROR.getCode(), e.getMessage()==null?ResultEnum.ERROR.getMsg():e.getMessage());
|
||||
return Response.error(ResultEnum.ERROR.getCode(), e.getMessage() == null ? ResultEnum.ERROR.getMsg() : e.getMessage());
|
||||
}
|
||||
|
||||
/**
|
||||
* 处理参数校验异常
|
||||
*
|
||||
* @param e
|
||||
* @return ResponseData
|
||||
*/
|
||||
@@ -63,19 +64,22 @@ public class ExceptionCatch {
|
||||
@ExceptionHandler(BindException.class)
|
||||
public Response<String> bindExceptionHandler(BindException e) {
|
||||
log.error("参数错误bind:{}", e.getBindingResult().getAllErrors().get(0).getDefaultMessage());
|
||||
return Response.fail(ResultEnum.FAIL.getCode(), e.getBindingResult().getAllErrors().get(0).getDefaultMessage());
|
||||
BusinessException businessException = new BusinessException(e.getBindingResult().getAllErrors().get(0).getDefaultMessage());
|
||||
return Response.error(businessException.getCode(), businessException.getMsg());
|
||||
}
|
||||
|
||||
/**
|
||||
* 处理参数校验异常
|
||||
*
|
||||
* @param e
|
||||
* @return ResponseData
|
||||
*/
|
||||
@ResponseBody
|
||||
@ExceptionHandler(MethodArgumentNotValidException.class)
|
||||
public Response<String> methodArgumentNotValidExceptionHandler(MethodArgumentNotValidException e) {
|
||||
public Response<String> handleValidationException(MethodArgumentNotValidException e) {
|
||||
log.error("参数错误bind:{}", e.getBindingResult().getAllErrors().get(0).getDefaultMessage());
|
||||
return Response.fail(ResultEnum.FAIL.getCode(), e.getBindingResult().getAllErrors().get(0).getDefaultMessage());
|
||||
BusinessException businessException = new BusinessException(e.getBindingResult().getAllErrors().get(0).getDefaultMessage());
|
||||
return Response.error(businessException.getCode(), businessException.getMsg());
|
||||
}
|
||||
|
||||
//初始化,不可预知异常自定义错误编码
|
||||
|
||||
@@ -0,0 +1,12 @@
|
||||
package com.ai.da.common.config.exception;
|
||||
|
||||
public class TokenMissingOrExpiredException extends RuntimeException {
|
||||
public TokenMissingOrExpiredException(String message) {
|
||||
super(message);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Throwable fillInStackTrace() {
|
||||
return this;
|
||||
}
|
||||
}
|
||||
@@ -1,12 +1,12 @@
|
||||
package com.ai.da.common.config.mybatis.plus;
|
||||
|
||||
import com.baomidou.mybatisplus.core.conditions.Wrapper;
|
||||
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
|
||||
import com.baomidou.mybatisplus.core.metadata.IPage;
|
||||
import com.baomidou.mybatisplus.core.toolkit.Constants;
|
||||
import org.apache.ibatis.annotations.Param;
|
||||
|
||||
public interface CommonMapper<T> extends BaseMapper<T> {
|
||||
|
||||
IPage<T> voPage(IPage<T> page, @Param(Constants.WRAPPER) Wrapper<T> queryWrapper);
|
||||
}
|
||||
package com.ai.da.common.config.mybatis.plus;
|
||||
|
||||
import com.baomidou.mybatisplus.core.conditions.Wrapper;
|
||||
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
|
||||
import com.baomidou.mybatisplus.core.metadata.IPage;
|
||||
import com.baomidou.mybatisplus.core.toolkit.Constants;
|
||||
import org.apache.ibatis.annotations.Param;
|
||||
|
||||
public interface CommonMapper<T> extends BaseMapper<T> {
|
||||
|
||||
IPage<T> voPage(IPage<T> page, @Param(Constants.WRAPPER) Wrapper<T> queryWrapper);
|
||||
}
|
||||
|
||||
@@ -1,48 +1,48 @@
|
||||
package com.ai.da.common.config.mybatis.plus;
|
||||
|
||||
import cn.hutool.core.collection.CollUtil;
|
||||
import com.ai.da.common.response.PageResponse;
|
||||
import com.ai.da.common.response.Response;
|
||||
import com.baomidou.mybatisplus.core.metadata.IPage;
|
||||
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
||||
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.function.Consumer;
|
||||
import java.util.function.Function;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
|
||||
public class CommonServiceImpl<M extends CommonMapper<T>, T, E> extends ServiceImpl<M, T> {
|
||||
|
||||
public PageResponse<E> voPage(QueryCriteria<T, E> criteria) {
|
||||
IPage<T> tPage = baseMapper.voPage(new Page<>(criteria.getPage(), criteria.getLimit()), criteria.buildWrapper());
|
||||
if (criteria.getMapper() != null && tPage != null && CollUtil.isNotEmpty(tPage.getRecords())) {
|
||||
List<E> convert = convert(tPage, criteria.getMapper(), criteria);
|
||||
Response<List<E>> response = Response.success(convert);
|
||||
PageResponse<E> pageResponse = new PageResponse<>(response, tPage.getCurrent(), tPage.getSize(), tPage.getTotal(), tPage.getPages());
|
||||
if (criteria.getPeekAllAfter() != null) {
|
||||
Consumer<List<E>> peekAllAfter = criteria.getPeekAllAfter();
|
||||
peekAllAfter.accept(pageResponse.getData());
|
||||
}
|
||||
return pageResponse;
|
||||
}
|
||||
PageResponse<E> pageResponse = new PageResponse<>(null, criteria.getPage(), criteria.getLimit(), 0, 0);
|
||||
if (criteria.getPeekAllAfter() != null) {
|
||||
Consumer<List<E>> peekAllAfter = criteria.getPeekAllAfter();
|
||||
peekAllAfter.accept(pageResponse.getData());
|
||||
}
|
||||
return pageResponse;
|
||||
}
|
||||
|
||||
List<E> convert(IPage<T> page, Function<? super T, E> mapper, QueryCriteria<T, E> criteria) {
|
||||
if (criteria.getPeekBefore() != null && criteria.getPeekAfter() != null) {
|
||||
return page.getRecords().stream().peek(criteria.getPeekBefore()).map(mapper).peek(criteria.getPeekAfter()).collect(Collectors.toList());
|
||||
} else if (criteria.getPeekBefore() != null && criteria.getPeekAfter() == null) {
|
||||
return page.getRecords().stream().peek(criteria.getPeekBefore()).map(mapper).collect(Collectors.toList());
|
||||
} else if (criteria.getPeekBefore() == null && criteria.getPeekAfter() != null) {
|
||||
return page.getRecords().stream().map(mapper).peek(criteria.getPeekAfter()).collect(Collectors.toList());
|
||||
}
|
||||
return page.getRecords().stream().map(mapper).collect(Collectors.toList());
|
||||
}
|
||||
}
|
||||
package com.ai.da.common.config.mybatis.plus;
|
||||
|
||||
import cn.hutool.core.collection.CollUtil;
|
||||
import com.ai.da.common.response.PageResponse;
|
||||
import com.ai.da.common.response.Response;
|
||||
import com.baomidou.mybatisplus.core.metadata.IPage;
|
||||
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
||||
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.function.Consumer;
|
||||
import java.util.function.Function;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
|
||||
public class CommonServiceImpl<M extends CommonMapper<T>, T, E> extends ServiceImpl<M, T> {
|
||||
|
||||
public PageResponse<E> voPage(QueryCriteria<T, E> criteria) {
|
||||
IPage<T> tPage = baseMapper.voPage(new Page<>(criteria.getPage(), criteria.getLimit()), criteria.buildWrapper());
|
||||
if (criteria.getMapper() != null && tPage != null && CollUtil.isNotEmpty(tPage.getRecords())) {
|
||||
List<E> convert = convert(tPage, criteria.getMapper(), criteria);
|
||||
Response<List<E>> response = Response.success(convert);
|
||||
PageResponse<E> pageResponse = new PageResponse<>(response, tPage.getCurrent(), tPage.getSize(), tPage.getTotal(), tPage.getPages());
|
||||
if (criteria.getPeekAllAfter() != null) {
|
||||
Consumer<List<E>> peekAllAfter = criteria.getPeekAllAfter();
|
||||
peekAllAfter.accept(pageResponse.getData());
|
||||
}
|
||||
return pageResponse;
|
||||
}
|
||||
PageResponse<E> pageResponse = new PageResponse<>(null, criteria.getPage(), criteria.getLimit(), 0, 0);
|
||||
if (criteria.getPeekAllAfter() != null) {
|
||||
Consumer<List<E>> peekAllAfter = criteria.getPeekAllAfter();
|
||||
peekAllAfter.accept(pageResponse.getData());
|
||||
}
|
||||
return pageResponse;
|
||||
}
|
||||
|
||||
List<E> convert(IPage<T> page, Function<? super T, E> mapper, QueryCriteria<T, E> criteria) {
|
||||
if (criteria.getPeekBefore() != null && criteria.getPeekAfter() != null) {
|
||||
return page.getRecords().stream().peek(criteria.getPeekBefore()).map(mapper).peek(criteria.getPeekAfter()).collect(Collectors.toList());
|
||||
} else if (criteria.getPeekBefore() != null && criteria.getPeekAfter() == null) {
|
||||
return page.getRecords().stream().peek(criteria.getPeekBefore()).map(mapper).collect(Collectors.toList());
|
||||
} else if (criteria.getPeekBefore() == null && criteria.getPeekAfter() != null) {
|
||||
return page.getRecords().stream().map(mapper).peek(criteria.getPeekAfter()).collect(Collectors.toList());
|
||||
}
|
||||
return page.getRecords().stream().map(mapper).collect(Collectors.toList());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,19 +1,19 @@
|
||||
package com.ai.da.common.config.mybatis.plus;
|
||||
|
||||
import com.baomidou.mybatisplus.core.injector.AbstractMethod;
|
||||
import com.baomidou.mybatisplus.core.injector.DefaultSqlInjector;
|
||||
import com.baomidou.mybatisplus.core.metadata.TableInfo;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@Configuration
|
||||
public class CustomerSqlInjector extends DefaultSqlInjector {
|
||||
|
||||
@Override
|
||||
public List<AbstractMethod> getMethodList(Class<?> mapperClass, TableInfo tableInfo) {
|
||||
List<AbstractMethod> methodList = super.getMethodList(mapperClass, tableInfo);
|
||||
methodList.add(new SelectVoPage());
|
||||
return methodList;
|
||||
}
|
||||
}
|
||||
package com.ai.da.common.config.mybatis.plus;
|
||||
|
||||
import com.baomidou.mybatisplus.core.injector.AbstractMethod;
|
||||
import com.baomidou.mybatisplus.core.injector.DefaultSqlInjector;
|
||||
import com.baomidou.mybatisplus.core.metadata.TableInfo;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@Configuration
|
||||
public class CustomerSqlInjector extends DefaultSqlInjector {
|
||||
|
||||
@Override
|
||||
public List<AbstractMethod> getMethodList(Class<?> mapperClass, TableInfo tableInfo) {
|
||||
List<AbstractMethod> methodList = super.getMethodList(mapperClass, tableInfo);
|
||||
methodList.add(new SelectVoPage());
|
||||
return methodList;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,85 +1,85 @@
|
||||
package com.ai.da.common.config.mybatis.plus;
|
||||
|
||||
import cn.hutool.core.util.StrUtil;
|
||||
import com.ai.da.common.annotation.Condition;
|
||||
import com.ai.da.common.annotation.Order;
|
||||
import com.ai.da.common.enums.ConditionType;
|
||||
import com.ai.da.common.utils.ConvertUtil;
|
||||
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
|
||||
import lombok.Data;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
|
||||
import java.lang.reflect.Field;
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
import java.util.function.Consumer;
|
||||
import java.util.function.Function;
|
||||
|
||||
/**
|
||||
* @author: dangweijian
|
||||
* @description:
|
||||
* @create: 2020-09-14 15:47
|
||||
**/
|
||||
@Data
|
||||
@Slf4j
|
||||
public abstract class QueryCriteria<T,E> {
|
||||
|
||||
private long page = 1;
|
||||
private long limit = 10;
|
||||
private Function<T, E> mapper;
|
||||
private Consumer<QueryWrapper<T>> appendWrapper;
|
||||
private Consumer<T> peekBefore;
|
||||
private Consumer<E> peekAfter;
|
||||
private Consumer<List<E>> peekAllAfter;
|
||||
|
||||
public QueryCriteria(Function<T, E> mapper) {
|
||||
this.mapper = mapper;
|
||||
}
|
||||
|
||||
public QueryWrapper<T> buildWrapper(){
|
||||
QueryWrapper<T> wrapper = new QueryWrapper<>();
|
||||
Field[] fields = this.getClass().getDeclaredFields();
|
||||
for (Field field : fields) {
|
||||
Condition condition = field.getAnnotation(Condition.class);
|
||||
if(condition != null){
|
||||
field.setAccessible(true);
|
||||
Object value = null;
|
||||
try {
|
||||
value = field.get(this);
|
||||
} catch (IllegalAccessException e) {
|
||||
log.warn("reflection anomaly!");
|
||||
}
|
||||
if(!StrUtil.isEmptyIfStr(value)){
|
||||
switch (condition.type()){
|
||||
case EQ:
|
||||
wrapper.eq(ConvertUtil.humpToLine2(field.getName()), value);
|
||||
break;
|
||||
case LIKE:
|
||||
wrapper.like(ConvertUtil.humpToLine2(field.getName()), value);
|
||||
case BETWEEN:
|
||||
if(value instanceof Collection && ((List) value).size() >= 2){
|
||||
wrapper.between(ConvertUtil.humpToLine2(field.getName()), ((List)value).get(0), ((List)value).get(1));
|
||||
}
|
||||
default:
|
||||
}
|
||||
}else if(condition.isNull()){
|
||||
wrapper.isNull(ConvertUtil.humpToLine2(field.getName()));
|
||||
}
|
||||
}
|
||||
Order order = field.getAnnotation(Order.class);
|
||||
if(order != null){
|
||||
if(!StrUtil.isEmptyIfStr(order.order())){
|
||||
switch (order.order()){
|
||||
case DESC:
|
||||
wrapper.orderByDesc(ConvertUtil.humpToLine2(field.getName()));
|
||||
break;
|
||||
case ASC:
|
||||
wrapper.orderByAsc(ConvertUtil.humpToLine2(field.getName()));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
wrapper.func(this.getAppendWrapper() != null, this.getAppendWrapper());
|
||||
return wrapper;
|
||||
}
|
||||
}
|
||||
package com.ai.da.common.config.mybatis.plus;
|
||||
|
||||
import cn.hutool.core.util.StrUtil;
|
||||
import com.ai.da.common.annotation.Condition;
|
||||
import com.ai.da.common.annotation.Order;
|
||||
import com.ai.da.common.enums.ConditionType;
|
||||
import com.ai.da.common.utils.ConvertUtil;
|
||||
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
|
||||
import lombok.Data;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
|
||||
import java.lang.reflect.Field;
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
import java.util.function.Consumer;
|
||||
import java.util.function.Function;
|
||||
|
||||
/**
|
||||
* @author: dangweijian
|
||||
* @description:
|
||||
* @create: 2020-09-14 15:47
|
||||
**/
|
||||
@Data
|
||||
@Slf4j
|
||||
public abstract class QueryCriteria<T, E> {
|
||||
|
||||
private long page = 1;
|
||||
private long limit = 10;
|
||||
private Function<T, E> mapper;
|
||||
private Consumer<QueryWrapper<T>> appendWrapper;
|
||||
private Consumer<T> peekBefore;
|
||||
private Consumer<E> peekAfter;
|
||||
private Consumer<List<E>> peekAllAfter;
|
||||
|
||||
public QueryCriteria(Function<T, E> mapper) {
|
||||
this.mapper = mapper;
|
||||
}
|
||||
|
||||
public QueryWrapper<T> buildWrapper() {
|
||||
QueryWrapper<T> wrapper = new QueryWrapper<>();
|
||||
Field[] fields = this.getClass().getDeclaredFields();
|
||||
for (Field field : fields) {
|
||||
Condition condition = field.getAnnotation(Condition.class);
|
||||
if (condition != null) {
|
||||
field.setAccessible(true);
|
||||
Object value = null;
|
||||
try {
|
||||
value = field.get(this);
|
||||
} catch (IllegalAccessException e) {
|
||||
log.warn("reflection anomaly!");
|
||||
}
|
||||
if (!StrUtil.isEmptyIfStr(value)) {
|
||||
switch (condition.type()) {
|
||||
case EQ:
|
||||
wrapper.eq(ConvertUtil.humpToLine2(field.getName()), value);
|
||||
break;
|
||||
case LIKE:
|
||||
wrapper.like(ConvertUtil.humpToLine2(field.getName()), value);
|
||||
case BETWEEN:
|
||||
if (value instanceof Collection && ((List) value).size() >= 2) {
|
||||
wrapper.between(ConvertUtil.humpToLine2(field.getName()), ((List) value).get(0), ((List) value).get(1));
|
||||
}
|
||||
default:
|
||||
}
|
||||
} else if (condition.isNull()) {
|
||||
wrapper.isNull(ConvertUtil.humpToLine2(field.getName()));
|
||||
}
|
||||
}
|
||||
Order order = field.getAnnotation(Order.class);
|
||||
if (order != null) {
|
||||
if (!StrUtil.isEmptyIfStr(order.order())) {
|
||||
switch (order.order()) {
|
||||
case DESC:
|
||||
wrapper.orderByDesc(ConvertUtil.humpToLine2(field.getName()));
|
||||
break;
|
||||
case ASC:
|
||||
wrapper.orderByAsc(ConvertUtil.humpToLine2(field.getName()));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
wrapper.func(this.getAppendWrapper() != null, this.getAppendWrapper());
|
||||
return wrapper;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,22 +1,22 @@
|
||||
package com.ai.da.common.config.mybatis.plus;
|
||||
|
||||
import com.baomidou.mybatisplus.core.enums.SqlMethod;
|
||||
import com.baomidou.mybatisplus.core.injector.AbstractMethod;
|
||||
import com.baomidou.mybatisplus.core.metadata.TableInfo;
|
||||
import org.apache.ibatis.mapping.MappedStatement;
|
||||
import org.apache.ibatis.mapping.SqlSource;
|
||||
|
||||
public class SelectVoPage extends AbstractMethod {
|
||||
|
||||
private static final String MAPPER_METHOD = "voPage";
|
||||
|
||||
public SelectVoPage() {
|
||||
super(MAPPER_METHOD);
|
||||
}
|
||||
|
||||
public MappedStatement injectMappedStatement(Class<?> mapperClass, Class<?> modelClass, TableInfo tableInfo) {
|
||||
String sql = String.format(SqlMethod.SELECT_PAGE.getSql(), this.sqlFirst(), this.sqlSelectColumns(tableInfo, true), tableInfo.getTableName(), this.sqlWhereEntityWrapper(true, tableInfo), this.sqlOrderBy(tableInfo), this.sqlComment());
|
||||
SqlSource sqlSource = this.languageDriver.createSqlSource(this.configuration, sql, modelClass);
|
||||
return this.addSelectMappedStatementForTable(mapperClass, MAPPER_METHOD, sqlSource, tableInfo);
|
||||
}
|
||||
}
|
||||
package com.ai.da.common.config.mybatis.plus;
|
||||
|
||||
import com.baomidou.mybatisplus.core.enums.SqlMethod;
|
||||
import com.baomidou.mybatisplus.core.injector.AbstractMethod;
|
||||
import com.baomidou.mybatisplus.core.metadata.TableInfo;
|
||||
import org.apache.ibatis.mapping.MappedStatement;
|
||||
import org.apache.ibatis.mapping.SqlSource;
|
||||
|
||||
public class SelectVoPage extends AbstractMethod {
|
||||
|
||||
private static final String MAPPER_METHOD = "voPage";
|
||||
|
||||
public SelectVoPage() {
|
||||
super(MAPPER_METHOD);
|
||||
}
|
||||
|
||||
public MappedStatement injectMappedStatement(Class<?> mapperClass, Class<?> modelClass, TableInfo tableInfo) {
|
||||
String sql = String.format(SqlMethod.SELECT_PAGE.getSql(), this.sqlFirst(), this.sqlSelectColumns(tableInfo, true), tableInfo.getTableName(), this.sqlWhereEntityWrapper(true, tableInfo), this.sqlOrderBy(tableInfo), this.sqlComment());
|
||||
SqlSource sqlSource = this.languageDriver.createSqlSource(this.configuration, sql, modelClass);
|
||||
return this.addSelectMappedStatementForTable(mapperClass, MAPPER_METHOD, sqlSource, tableInfo);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,37 +0,0 @@
|
||||
package com.ai.da.common.config.swagger;
|
||||
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import springfox.documentation.builders.ApiInfoBuilder;
|
||||
import springfox.documentation.builders.PathSelectors;
|
||||
import springfox.documentation.builders.RequestHandlerSelectors;
|
||||
import springfox.documentation.service.Contact;
|
||||
import springfox.documentation.spi.DocumentationType;
|
||||
import springfox.documentation.spring.web.plugins.Docket;
|
||||
import springfox.documentation.swagger2.annotations.EnableSwagger2WebMvc;
|
||||
|
||||
@Configuration
|
||||
@EnableSwagger2WebMvc
|
||||
public class AidaConfiguration {
|
||||
|
||||
@Bean(value = "IntelligentCurtainApis")
|
||||
public Docket gxyd5aThemeApis() {
|
||||
Contact contact = new Contact("Mr.Y","","136");
|
||||
|
||||
Docket docket=new Docket(DocumentationType.SWAGGER_2)
|
||||
.apiInfo(new ApiInfoBuilder()
|
||||
.description("aida接口文档")
|
||||
.contact(contact)
|
||||
.termsOfServiceUrl("暂无")
|
||||
.version("1.0")
|
||||
.build())
|
||||
//分组名称
|
||||
.groupName("1.0")
|
||||
.select()
|
||||
//这里指定Controller扫描包路径
|
||||
.apis(RequestHandlerSelectors.basePackage("com.ai.da.controller"))
|
||||
.paths(PathSelectors.any())
|
||||
.build();
|
||||
return docket;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
package com.ai.da.common.constant;
|
||||
|
||||
public class AffiliateConstants {
|
||||
public static final String STATUS_ACTIVE = "Active";
|
||||
public static final String STATUS_INACTIVE = "Inactive";
|
||||
public static final String STATUS_DELETE = "Delete";
|
||||
public static final Integer DELETED = 1;
|
||||
public static final Integer NOT_DELETED = 0;
|
||||
}
|
||||
@@ -0,0 +1,20 @@
|
||||
package com.ai.da.common.constant;
|
||||
|
||||
public class AlipayHKConstant {
|
||||
|
||||
// 服务名
|
||||
public static final String CREATE_ORDER = "create_order";
|
||||
public static final String ORDER_DETAILS = "order_details";
|
||||
public static final String TRANSACTION_DETAILS = "transaction_details";
|
||||
public static final String GET_FILE = "get_file";
|
||||
public static final String CREATE_AUTO_DEBIT = "create_auto_debit";
|
||||
public static final String REFRESH_TRANSACTION_STATUS = "refresh_transaction_status";
|
||||
public static final String REFUND_TRANSACTION = "refund_transaction";
|
||||
|
||||
// 订单状态
|
||||
public static final String STATUS_NEW = "new";
|
||||
public static final String STATUS_WAIT = "wait";
|
||||
public static final String STATUS_PAID = "paid";
|
||||
public static final String STATUS_EXPIRED = "expired";
|
||||
public static final String STATUS_LIQUIDATED = "liquidated";
|
||||
}
|
||||
98
src/main/java/com/ai/da/common/constant/CommonConstant.java
Normal file
98
src/main/java/com/ai/da/common/constant/CommonConstant.java
Normal file
@@ -0,0 +1,98 @@
|
||||
package com.ai.da.common.constant;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
public class CommonConstant {
|
||||
// 单位 秒 10分钟过期
|
||||
// public static final Long TASK_EXPIRE_TIME = 24 * 60 * 60L;
|
||||
public static final Long TASK_EXPIRE_TIME = 10 * 60L;
|
||||
// 单位 秒 两天过期
|
||||
public static final Long CREDITS_EXPIRE_TIME = 2 * 24 * 60 * 60L;
|
||||
// 单位 分钟
|
||||
public static final Integer MINIO_IMAGE_EXPIRE_TIME = 24 * 60;
|
||||
// 单位 秒 一天过期 in redis
|
||||
public static final Long GENERATE_RESULT_EXPIRE_TIME = 24 * 60 * 60L;
|
||||
// 单位 秒 7天过期
|
||||
public static final Long REDIS_SET_EXPIRE_TIME = 24 * 60 * 60 * 7L;
|
||||
|
||||
public static class Numbers{
|
||||
public static final Integer NUMBER_10 = 10;
|
||||
public static final Integer NUMBER_1000 = 1000;
|
||||
public static final Integer NUMBER_10080 = 10080;
|
||||
}
|
||||
|
||||
public static final String GENERATE_PATH = "/api/generate_image";
|
||||
public static final String GENERATE_PATH_FLUX2_KLEIN = "/api/generate_image_flux2_klein";
|
||||
|
||||
public static final String GENERATE_SINGLE_LOGO = "/api/generate_single_logo";
|
||||
|
||||
public static final String GENERATE_SLOGAN = "/api/slogan";
|
||||
|
||||
public static final String GENERATE_CANCEL = "/api/generate_cancel/";
|
||||
|
||||
public static final String GENERATE_LOGO_SINGLE_CANCEL = "/api/generate_single_logo_cancel/";
|
||||
|
||||
// public static final String POSE_TRANSFORMATION_CANCEL = "/api/pose_transform_cancel/";
|
||||
public static final String POSE_TRANSFORMATION_CANCEL = "/api/comfyui_i_2_video_cancel/";
|
||||
|
||||
public static final String PYTHON_PORT_9996 = "9996";
|
||||
|
||||
public static final String PYTHON_PORT_9997 = "9997";
|
||||
|
||||
public static final List<String> AGES_EN = Arrays.asList("Below 20", "20-30", "30-40", "40+");
|
||||
|
||||
public static final List<String> AGES_CN = Arrays.asList("20岁以下", "20-30岁", "30-40岁", "40+岁");
|
||||
public static final List<String> IF_HELPFUL_EN = Arrays.asList("Easy to learn and use", "Easy to get trend information",
|
||||
"Lots of creative design proposals","The AIGC functions for moodboard is helpful","The AIGC functions for design sketches is helpful",
|
||||
"Easy to select the right color","The Chatbot function is helpful","The print position function is helpful",
|
||||
"The drawing function is helpful","The export function is useful","Easy to edit the design","Others");
|
||||
|
||||
public static final List<String> IF_HELPFUL_CN = Arrays.asList("易于学习和使用", "容易获取趋势信息",
|
||||
"提供大量创意设计方案","AIGC功能对灵感板有帮助","AIGC功能对设计草图有帮助",
|
||||
"容易选择合适的颜色","聊天机器人功能有帮助","打印位置功能有帮助",
|
||||
"绘图功能有帮助","导出功能有用","设计编辑简单","其他");
|
||||
|
||||
public static final List<String> IF_IMPROVE_EN = Arrays.asList("Proposed designs are boring, need more interesting designs",
|
||||
"Difficult to make changes on design","Only 2D output, no 3D results","Difficult to apply keywords for AIGC generation",
|
||||
"Clothing is not in the right proportion","Not compatible with pattern making solutions","Improved user interface for better navigation",
|
||||
"Lack of responsive customer support","Insufficient tutorial or guidance for new users","Limited personalization options for designs","Others");
|
||||
|
||||
public static final List<String> IF_IMPROVE_CN = Arrays.asList("提供的设计很无聊,需要更多有趣的设计",
|
||||
"设计修改困难","只有2D输出,没有3D结果","难以选择合适的关键词应用于AIGC生成",
|
||||
"服装比例不正确","与打版解决方案不兼容","改进用户界面以便更好导航",
|
||||
"客户支持响应不及时","对新用户的教程或指导不足","设计个性化选项有限","其他");
|
||||
|
||||
public static final List<String> IS_SUBSCRIBE = Arrays.asList("yes", "no");
|
||||
|
||||
// public static final String DEFAULT_AVATAR = "aida-users/87/avatar/default.jpg";
|
||||
public static final String DEFAULT_AVATAR = "aida-users/87/avatar/default.png";
|
||||
|
||||
/* 截止至2024/08/26,在Code-Create DB中pmr_users表中最大的用户id */
|
||||
public static final Long MAXIMUM_USER_ID = 704L;
|
||||
// public static final Long MAXIMUM_USER_ID = 225L;
|
||||
|
||||
// 激活更改邮箱 链接有效期 毫秒 3天
|
||||
public static final Long CHANGE_MAILBOX_LINK_VALIDITY = 259200000L;
|
||||
|
||||
public static final String RCA_WORKSHOP_TAG = "#RCAworkshop_2024";
|
||||
|
||||
public static final String PORTFOLIO_DELETED_EN = "Portfolio has been deleted";
|
||||
|
||||
public static final String PORTFOLIO_DELETED_CN = "作品已删除";
|
||||
|
||||
public static final String TIME_FORMAT_MMM_dd_yyyy_EEEE = "MMM. dd, yyyy, EEEE";
|
||||
|
||||
public static final String TIME_FORMAT_MMM_dd_yyyy = "MMM. dd, yyyy";
|
||||
|
||||
public static final String TIME_FORMAT_yyyy_MM_dd_HH_mm_ss = "yyyy-MM-dd HH:mm:ss";
|
||||
|
||||
public static final String AFFILIATE_LINK = "https://www.aida.com.hk?ref=";
|
||||
|
||||
public static final String PARTIAL_DESIGN_FILENAME = "PartialDesign";
|
||||
|
||||
public static final String PARTIAL_DESIGN_PREVIEW_FILENAME = "Preview";
|
||||
|
||||
public static final String senderEmail = "info@aida.com.hk";
|
||||
|
||||
}
|
||||
42
src/main/java/com/ai/da/common/constant/ModelConstants.java
Normal file
42
src/main/java/com/ai/da/common/constant/ModelConstants.java
Normal file
@@ -0,0 +1,42 @@
|
||||
package com.ai.da.common.constant;
|
||||
|
||||
/**
|
||||
* 模型相关常量类
|
||||
* 用于存放 chooseModelAndPrompt 方法中的字符串常量
|
||||
*/
|
||||
public class ModelConstants {
|
||||
|
||||
// 类型常量
|
||||
public static final String PRINTBOARD = "Printboard";
|
||||
public static final String MOODBOARD = "Moodboard";
|
||||
public static final String SKETCHBOARD = "Sketchboard";
|
||||
|
||||
// 模型级别常量
|
||||
public static final String ADVANCED = "advanced";
|
||||
public static final String HIGH = "high";
|
||||
public static final String NORMAL = "normal";
|
||||
|
||||
// 模型名称常量
|
||||
public static final String PRINTBOARD_ADVANCED_T2I = "qwen-image";
|
||||
public static final String MOODBOARD_ADVANCED = "doubao-seedream-3-0-t2i-250415";
|
||||
public static final String PRINTBOARD_HIGH_T2I = "doubao-seedream-3-0-t2i-250415";
|
||||
public static final String PRINTBOARD_HIGH_I2I = "doubao-seedream-4-0-250828-fast";
|
||||
public static final String PRINTBOARD_ADVANCED_I2I = "doubao-seedream-4-0-250828";
|
||||
public static final String IMAGEN_MODEL = "imagen-4.0-generate-001";
|
||||
public static final String NANO_BANANA = "gemini-2.5-flash-image";
|
||||
public static final String LOCAL_MODEL = "local";
|
||||
|
||||
// 风格常量
|
||||
public static final String PAINTING_STYLE = "Painting Style";
|
||||
public static final String ILLUSTRATION_STYLE = "Illustration Style";
|
||||
public static final String REAL_STYLE = "Real Style";
|
||||
|
||||
// 映射键
|
||||
public static final String PROMPT = "prompt";
|
||||
public static final String USE_MODEL = "UseModel";
|
||||
|
||||
// 防止实例化
|
||||
private ModelConstants() {
|
||||
throw new UnsupportedOperationException("This is a utility class and cannot be instantiated");
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,173 @@
|
||||
package com.ai.da.common.constant;
|
||||
|
||||
public class PayPalCheckoutConstant {
|
||||
|
||||
public static final String CAPTURE = "CAPTURE";
|
||||
/**
|
||||
* 该标签将覆盖PayPal网站上PayPal帐户中的公司名称
|
||||
*/
|
||||
public static final String BRANDNAME = "AIDA";
|
||||
/**
|
||||
* LOGIN。当客户单击PayPal Checkout时,客户将被重定向到页面以登录PayPal并批准付款。
|
||||
* BILLING。当客户单击PayPal Checkout时,客户将被重定向到一个页面,以输入信用卡或借记卡以及完成购买所需的其他相关账单信息
|
||||
* NO_PREFERENCE。当客户单击“ PayPal Checkout”时,将根据其先前的交互方式将其重定向到页面以登录PayPal并批准付款,或重定向至页面以输入信用卡或借记卡以及完成购买所需的其他相关账单信息使用PayPal。
|
||||
* 默认值:NO_PREFERENCE
|
||||
*/
|
||||
public static final String LANDINGPAGE = "NO_PREFERENCE";
|
||||
/**
|
||||
* CONTINUE。将客户重定向到PayPal付款页面后,将出现“ 继续”按钮。当结帐流程启动时最终金额未知时,请使用此选项,并且您想将客户重定向到商家页面而不处理付款。
|
||||
* PAY_NOW。将客户重定向到PayPal付款页面后,出现“ 立即付款”按钮。当启动结帐时知道最终金额并且您要在客户单击“ 立即付款”时立即处理付款时,请使用此选项。
|
||||
*/
|
||||
public static final String USERACTION = "PAY_NOW";
|
||||
/**
|
||||
* GET_FROM_FILE。使用贝宝网站上客户提供的送货地址。
|
||||
* NO_SHIPPING。从PayPal网站编辑送货地址。推荐用于数字商品
|
||||
* SET_PROVIDED_ADDRESS。使用商家提供的地址。客户无法在PayPal网站上更改此地址
|
||||
*/
|
||||
// public static final String SHIPPINGPREFERENCE = "SET_PROVIDED_ADDRESS";
|
||||
public static final String SHIPPINGPREFERENCE = "NO_SHIPPING";
|
||||
/**
|
||||
* 交易异常
|
||||
*/
|
||||
public static final String FAILURE = "failure";
|
||||
/**
|
||||
* 交易成功
|
||||
*/
|
||||
public static final String SUCCESS = "success";
|
||||
|
||||
/**
|
||||
* ipn回调。支付成功
|
||||
*/
|
||||
public static final String PAYMENT_STATUS_COMPLETED = "Completed";
|
||||
/**
|
||||
* ipn回调。退款成功
|
||||
*/
|
||||
public static final String PAYMENT_STATUS_REFUNDED = "Refunded";
|
||||
/**
|
||||
* ipn回调。待定
|
||||
*/
|
||||
public static final String PAYMENT_STATUS_PENDING = "Pending";
|
||||
|
||||
/**
|
||||
* ipn回调,付款因退款或其他类型的冲销而被冲销。资金已从您的帐户余额中删除,并退还给买方
|
||||
*/
|
||||
public static final String PAYMENT_STATUS_REVERSED = "Reversed";
|
||||
|
||||
/**
|
||||
* ipn回调, 撤销已被取消。例如,您赢得了与客户的纠纷,并且撤回的交易资金已退还给您
|
||||
*/
|
||||
public static final String PAYMENT_STATUS_CANCELED_REVERSAL = "Canceled_Reversal";
|
||||
|
||||
/**
|
||||
* ipn回调,付款被拒绝
|
||||
*/
|
||||
public static final String PAYMENT_STATUS_DENIED = "Denied";
|
||||
|
||||
/**
|
||||
* ipn回调, 此授权已过期,无法捕获
|
||||
*/
|
||||
public static final String PAYMENT_STATUS_EXPIRED = "Expired";
|
||||
|
||||
/**
|
||||
* ipn回调, 德国的ELV付款是通过Express Checkout进行的
|
||||
*/
|
||||
public static final String PAYMENT_STATUS_CREATED = "Created";
|
||||
|
||||
/**
|
||||
* ipn回调, 付款失败。仅当付款是通过您客户的银行帐户进行的。
|
||||
*/
|
||||
public static final String PAYMENT_STATUS_FAILED = "Failed";
|
||||
|
||||
/**
|
||||
* ipn回调,付款已被接受
|
||||
*/
|
||||
public static final String PAYMENT_STATUS_PROCESSED = "Processed";
|
||||
|
||||
/**
|
||||
* ipn回调,此授权已失效
|
||||
*/
|
||||
public static final String PAYMENT_STATUS_VOIDED = "Voided";
|
||||
|
||||
//订单状态
|
||||
/**
|
||||
* 1、支付完成;捕获的付款的资金已记入收款人的PayPal帐户
|
||||
* 2、退款完成;该交易的资金已记入客户的帐户
|
||||
*/
|
||||
public static final String STATE_COMPLETED = "COMPLETED";
|
||||
/**
|
||||
* 部分退款;少于所捕获付款金额的金额已部分退还给付款人。
|
||||
*/
|
||||
public static final String STATE_PARTIALLY_REFUNDED = "PARTIALLY_REFUNDED";
|
||||
|
||||
|
||||
/**
|
||||
* 1、支付待定;捕获的付款资金尚未记入收款人的PayPal帐户。有关更多信息请参见status.details。
|
||||
* 2、退款待定;有关更多信息,请参见status_details.reason。
|
||||
*/
|
||||
/**
|
||||
* 支付待定:
|
||||
* capture_status_details
|
||||
* reason 枚举
|
||||
* 捕获的付款状态为PENDING或DENIED的原因。可能的值为:
|
||||
* BUYER_COMPLAINT。付款人与贝宝(PayPal)对此捕获的付款提出了争议。
|
||||
* CHARGEBACK。响应于付款人与用于支付此已捕获付款的金融工具的发行人对此已捕获的付款提出异议,已收回的资金被撤回。
|
||||
* ECHECK。由尚未结清的电子支票支付的付款人。
|
||||
* INTERNATIONAL_WITHDRAWAL。访问您的在线帐户。在您的“帐户概览”中,接受并拒绝此笔付款。
|
||||
* OTHER。无法提供其他特定原因。有关此笔付款的更多信息,请在线访问您的帐户或联系PayPal。
|
||||
* PENDING_REVIEW。捕获的付款正在等待人工审核。
|
||||
*(手动收取)RECEIVING_PREFERENCE_MANDATES_MANUAL_ACTION。收款人尚未为其帐户设置适当的接收首选项。有关如何接受或拒绝此付款的更多信息,请在线访问您的帐户。通常在某些情况下提供此原因,例如,当所捕获付款的货币与收款人的主要持有货币不同时。
|
||||
* REFUNDED。收回的资金已退还。
|
||||
* TRANSACTION_APPROVED_AWAITING_FUNDING。付款人必须将这笔付款的资金汇出。通常,此代码适用于手动EFT。
|
||||
* UNILATERAL。收款人没有PayPal帐户。
|
||||
* VERIFICATION_REQUIRED。收款人的PayPal帐户未通过验证。
|
||||
*/
|
||||
/**
|
||||
* 退款待定
|
||||
* 退款具有“PENDING”或“FAILED”状态的原因。 可能的值为:
|
||||
* ECHECK。客户的帐户通过尚未结清的eCheck进行注资。
|
||||
*/
|
||||
public static final String STATE_PENDING = "PENDING";
|
||||
/**
|
||||
* 退款;大于或等于此捕获的付款金额的金额已退还给付款人
|
||||
*/
|
||||
public static final String STATE_REFUNDED = "REFUNDED";
|
||||
/**
|
||||
* 支付拒绝
|
||||
*/
|
||||
public static final String STATE_DENIED = "DENIED";
|
||||
/**
|
||||
* 退款失败
|
||||
*/
|
||||
public static final String STATE_FAILED = "FAILED";
|
||||
|
||||
/**
|
||||
* 争议状态
|
||||
*/
|
||||
public static final String BUYER_COMPLAINT = "BUYER_COMPLAINT";
|
||||
|
||||
/**
|
||||
* 沙箱环境请求网关地址
|
||||
*/
|
||||
public static final String SANDBOX = "https://api.sandbox.paypal.com";
|
||||
/**
|
||||
* 生产环境请求网关地址
|
||||
*/
|
||||
public static final String LIVE = "https://api.paypal.com";
|
||||
/**
|
||||
* 添加物流信息请求路径
|
||||
*/
|
||||
public static final String ADD_TRACK_URL = "/v1/shipping/trackers-batch";
|
||||
|
||||
/**
|
||||
* 修改物流信息请求路径
|
||||
*/
|
||||
public static final String UPDATE_TRACK_URL = "/v1/shipping/trackers/";
|
||||
|
||||
public final static String CMD_NOTIFY_VALIDATE = "_notify-validate";
|
||||
|
||||
public final static String PAYPAL_TOKEN_KEY = "PayPalAccessToken";
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
@@ -3,11 +3,12 @@ package com.ai.da.common.context;
|
||||
import com.ai.da.model.vo.AuthPrincipalVo;
|
||||
|
||||
public class UserContext {
|
||||
private static ThreadLocal<AuthPrincipalVo> userHolder= new ThreadLocal<AuthPrincipalVo>();
|
||||
private static ThreadLocal<AuthPrincipalVo> userHolder = new ThreadLocal<AuthPrincipalVo>();
|
||||
|
||||
public static AuthPrincipalVo getUserHolder() {
|
||||
return userHolder.get();
|
||||
}
|
||||
|
||||
public static void delete() {
|
||||
userHolder.remove();
|
||||
}
|
||||
|
||||
@@ -0,0 +1,39 @@
|
||||
package com.ai.da.common.enums;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Getter;
|
||||
|
||||
@AllArgsConstructor
|
||||
@Getter
|
||||
public enum AliPayTradeStateEnum {
|
||||
|
||||
/**
|
||||
* 支付成功
|
||||
*/
|
||||
SUCCESS("TRADE_SUCCESS"),
|
||||
|
||||
/**
|
||||
* 未支付
|
||||
*/
|
||||
NOTPAY("WAIT_BUYER_PAY"),
|
||||
|
||||
/**
|
||||
* 已关闭
|
||||
*/
|
||||
CLOSED("TRADE_CLOSED"),
|
||||
|
||||
/**
|
||||
* 退款成功
|
||||
*/
|
||||
REFUND_SUCCESS("REFUND_SUCCESS"),
|
||||
|
||||
/**
|
||||
* 退款失败
|
||||
*/
|
||||
REFUND_ERROR("REFUND_ERROR");
|
||||
|
||||
/**
|
||||
* 类型
|
||||
*/
|
||||
private final String type;
|
||||
}
|
||||
@@ -0,0 +1,45 @@
|
||||
package com.ai.da.common.enums;
|
||||
|
||||
import java.util.stream.Stream;
|
||||
|
||||
/**
|
||||
* @author: yanglei
|
||||
* @description: 操作类型 登入 忘记密码
|
||||
* @create: 2022-8-10 17:33
|
||||
**/
|
||||
public enum AuthenticationOperationTypeEnum {
|
||||
/**
|
||||
* 登入
|
||||
*/
|
||||
LOGIN,
|
||||
/**
|
||||
* 异常ip
|
||||
*/
|
||||
EXCEPTION_IP,
|
||||
/**
|
||||
* 绑定邮箱
|
||||
*/
|
||||
BIND_MAILBOX,
|
||||
/**
|
||||
* 忘记密码
|
||||
*/
|
||||
FORGET_PWD,
|
||||
/**
|
||||
* 更改邮箱
|
||||
*/
|
||||
CHANGE_MAILBOX,
|
||||
/**
|
||||
* 填写用户国家和职业
|
||||
*/
|
||||
UPDATE_USERINFO,
|
||||
|
||||
REGISTER,
|
||||
/**
|
||||
* Global_Award 活动验证
|
||||
*/
|
||||
GLOBAL_AWARD;
|
||||
|
||||
public static AuthenticationOperationTypeEnum of(String name) {
|
||||
return Stream.of(AuthenticationOperationTypeEnum.values()).filter(v -> v.name().equals(name)).findFirst().orElse(null);
|
||||
}
|
||||
}
|
||||
@@ -27,7 +27,9 @@ public enum CollectionLevel1TypeEnum {
|
||||
/**
|
||||
* 市场
|
||||
*/
|
||||
MARKETING_SKETCH("MarketingSketch");
|
||||
MARKETING_SKETCH("MarketingSketch"),
|
||||
|
||||
MODEL("Models");
|
||||
|
||||
private String realName;
|
||||
|
||||
@@ -39,8 +41,8 @@ public enum CollectionLevel1TypeEnum {
|
||||
return realName;
|
||||
}
|
||||
|
||||
public static CollectionLevel1TypeEnum uploadOf(String realName){
|
||||
public static CollectionLevel1TypeEnum uploadOf(String realName) {
|
||||
return Stream.of(CollectionLevel1TypeEnum.values())
|
||||
.filter(v ->v.getRealName().equals(realName)).findFirst().orElse(null);
|
||||
.filter(v -> v.getRealName().equals(realName)).findFirst().orElse(null);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
package com.ai.da.common.enums;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
/**
|
||||
@@ -27,7 +29,27 @@ public enum CollectionLevel2TypeEnum {
|
||||
/**
|
||||
* 裤子
|
||||
*/
|
||||
TROUSERS("Trousers");
|
||||
TROUSERS("Trousers"),
|
||||
/**
|
||||
* 男装上装
|
||||
*/
|
||||
TOPS("Tops"),
|
||||
/**
|
||||
* 男装下装
|
||||
*/
|
||||
BOTTOMS("Bottoms"),
|
||||
/**
|
||||
* 印花-logo
|
||||
*/
|
||||
LOGO("Logo"),
|
||||
/**
|
||||
* 印花-slogan
|
||||
*/
|
||||
SLOGAN("Slogan"),
|
||||
/**
|
||||
* 印花-图案
|
||||
*/
|
||||
Pattern("Pattern");
|
||||
|
||||
private String realName;
|
||||
|
||||
@@ -42,4 +64,11 @@ public enum CollectionLevel2TypeEnum {
|
||||
public static CollectionLevel2TypeEnum of(String realName) {
|
||||
return Stream.of(CollectionLevel2TypeEnum.values()).filter(v -> v.getRealName().equals(realName)).findFirst().orElse(null);
|
||||
}
|
||||
|
||||
public static List<String> printType() {
|
||||
return Arrays.asList(LOGO.getRealName(), SLOGAN.getRealName(), Pattern.getRealName());
|
||||
}
|
||||
public static CollectionLevel2TypeEnum ofWithLoweCase(String realName) {
|
||||
return Stream.of(CollectionLevel2TypeEnum.values()).filter(v -> v.getRealName().toLowerCase().equals(realName)).findFirst().orElse(null);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6,5 +6,5 @@ package com.ai.da.common.enums;
|
||||
* @create: 2020-01-14 17:33
|
||||
**/
|
||||
public enum ConditionType {
|
||||
EQ,LIKE,BETWEEN;
|
||||
EQ, LIKE, BETWEEN;
|
||||
}
|
||||
|
||||
91
src/main/java/com/ai/da/common/enums/CreditsEventsEnum.java
Normal file
91
src/main/java/com/ai/da/common/enums/CreditsEventsEnum.java
Normal file
@@ -0,0 +1,91 @@
|
||||
package com.ai.da.common.enums;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Getter;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.function.Function;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
@AllArgsConstructor
|
||||
@Getter
|
||||
public enum CreditsEventsEnum {
|
||||
|
||||
PRICE("price","10"),
|
||||
// PRICE("price","1"),// for test
|
||||
// PRICE("price","0.1"),
|
||||
|
||||
BUY_CREDITS("Buy Credits","50"),
|
||||
// BUY_CREDITS("Buy Credits","10"),// for test
|
||||
|
||||
REFUND("Refund","50"),
|
||||
// BUY_CREDITS("Buy Credits","10"),
|
||||
|
||||
// 每月更新
|
||||
INIT_YEARLY("init_yearly", "50000"),
|
||||
INIT_MONTHLY("init_monthly", "3500"),
|
||||
INIT_MONTHLY_ECO("init_monthly_eco", "500"),
|
||||
INIT_QUARTERLY("init_quarterly", "12000"),
|
||||
INIT_MONTHLY_EDU("init_monthly_edu", "3500"),
|
||||
INIT_TRIAL("init_trial", "100"),
|
||||
INIT_WEEKLY("init_weekly","6000"),
|
||||
RESET_YEAR_CREDITS("reset_year_credits","6000"),
|
||||
|
||||
// SUPER_RESOLUTION("Super Resolution","30"),
|
||||
SUPER_RESOLUTION("Super Resolution","10"),
|
||||
SLOGAN("Slogan","10"),
|
||||
LOGO("Logo","5"),
|
||||
PATTERN("Pattern","5"),
|
||||
MOOD_BOARD("MoodBoard","5"),
|
||||
SKETCH_BOARD("SketchBoard","5"),
|
||||
TO_PRODUCT_IMAGE("ToProductImage","5"),
|
||||
TO_PRODUCT_IMAGE_ADVANCED("ToProductImageAdvanced","15"),
|
||||
RELIGHT("Relight","5"),
|
||||
RELIGHT_FLUX("RelightFlux","10"),
|
||||
QUESTIONNAIRE("Questionnaire","100"),
|
||||
IMAGE_TO_SKETCH("ImageToSketch","5"),
|
||||
IMAGE_TO_SKETCH_FLUX("ImageToSketchFlux","10"),
|
||||
POSE_TRANSFORMATION("PoseTransformation","10"),
|
||||
OTHER("Other","5"),
|
||||
|
||||
SCETCH_TEXT2IMG("SketchText2Image","10"),
|
||||
SCETCH_IMG2IMG("SketchImg2Image","15"),
|
||||
WX_TEXT2IMG("WX_Text2Image", "5"),
|
||||
QWEN_TEXT2IMG("QWEN_Text2Image", "10"),
|
||||
DOUBAO_TEXT2IMG("Doubao_Text2Image", "10"),
|
||||
DOUBAO_IMG2IMG_ADVANCED("Doubao_img2image_advanced", "10"),
|
||||
DOUBAO_IMG2IMG_HIGH("Doubao_img2image_high", "15"),
|
||||
WX_ANIMATION("WX_Animation", "30"),
|
||||
FREEPIK_IMG2IMG("Freepik_img2img", "20"),
|
||||
FLUX_IMG2IMG("Flux_img2img","10"),
|
||||
|
||||
LOCAL_TEXT2IMG("Local_text2img","1.25"),
|
||||
LOCAL_IMG2IMG("Local_img2img","1.25"),
|
||||
LOCAL_TEXT2IMG_HIGH("Local_text2img_high","5"),
|
||||
LOCAL_IMG2IMG_HIGH("Local_img2img_high","5"),
|
||||
LOCAL_ANIMATION("Local_Animation","15"),
|
||||
|
||||
LLM_CONVERSATION("LLM_Conversation", "0")
|
||||
;
|
||||
|
||||
private final String name;
|
||||
|
||||
/**
|
||||
* 对应事件需要消耗or获得的积分
|
||||
*/
|
||||
private final String value;
|
||||
|
||||
public static List<String> generateFunctionNames() {
|
||||
return Arrays.asList(SLOGAN.name, LOGO.name, PATTERN.name, MOOD_BOARD.name, SKETCH_BOARD.name,
|
||||
TO_PRODUCT_IMAGE.name, RELIGHT.name, IMAGE_TO_SKETCH.name, POSE_TRANSFORMATION.name);
|
||||
}
|
||||
|
||||
private static final Map<String, CreditsEventsEnum> BY_TASK_NAME = Arrays.stream(values())
|
||||
.collect(Collectors.toMap(CreditsEventsEnum::getName, Function.identity()));
|
||||
|
||||
public static CreditsEventsEnum getByTaskName(String taskName){
|
||||
return BY_TASK_NAME.get(taskName);
|
||||
}
|
||||
}
|
||||
40
src/main/java/com/ai/da/common/enums/CurrencyCodesEnum.java
Normal file
40
src/main/java/com/ai/da/common/enums/CurrencyCodesEnum.java
Normal file
@@ -0,0 +1,40 @@
|
||||
package com.ai.da.common.enums;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Getter;
|
||||
|
||||
@Getter
|
||||
public enum CurrencyCodesEnum {
|
||||
|
||||
AUSTRALIAN_DOLLAR("AUD"),
|
||||
BRAZILIAN_REAL("BRL"),
|
||||
CANADIAN_DOLLAR("CAD"),
|
||||
CHINESE_RENMENBI("CNY"),
|
||||
CZECH_KORUNA("CZK"),
|
||||
DANISH_KRONE("DKK"),
|
||||
EURO("EUR"),
|
||||
HONG_KONG_DOLLAR("HKD"),
|
||||
HUNGARIAN_FORINT("HUF"),
|
||||
ISRAELI_NEW_SHEKEL("ILS"),
|
||||
JAPANESE_YEN("JPY"),
|
||||
MALAYSIAN_RINGGIT("MYR"),
|
||||
MEXICAN_PESO("MXN"),
|
||||
NEW_TAIWAN_DOLLAR("TWD"),
|
||||
NEW_ZEALAND_DOLLAR("NZD"),
|
||||
NORWEGIAN_KRONE("NOK"),
|
||||
PHILIPPINE_PESO("PHP"),
|
||||
POLISH_ZLOTY("PLN"),
|
||||
POUND_STERLING("GBP"),
|
||||
RUSSIAN_RUBLE("RUB"),
|
||||
SINGAPORE_DOLLAR("SGD"),
|
||||
SWEDISH_KRONA("SEK"),
|
||||
SWISS_FRANC("CHF"),
|
||||
THAI_BAHT("THB"),
|
||||
UNITED_STATES_DOLLAR("USD");
|
||||
|
||||
private String code;
|
||||
|
||||
CurrencyCodesEnum(String code) {
|
||||
this.code = code;
|
||||
}
|
||||
}
|
||||
@@ -16,19 +16,19 @@ public enum CurrentDesignPictureTypeEnum {
|
||||
/**
|
||||
* PIN
|
||||
*/
|
||||
PIN(1,"PIN"),
|
||||
PIN(1, "PIN"),
|
||||
/**
|
||||
* USER_LIBRARY
|
||||
*/
|
||||
USER_LIBRARY(2,"userLibrary"),
|
||||
// USER_LIBRARY(2, "userLibrary"),
|
||||
/**
|
||||
* SYS_FILE
|
||||
*/
|
||||
SYS_FILE(3,"sysFile"),
|
||||
SYS_FILE(2, "sysFile"),
|
||||
/**
|
||||
* noPIN
|
||||
*/
|
||||
NO_PIN(4,"noPIN");
|
||||
NO_PIN(3, "noPIN");
|
||||
|
||||
private Integer code;
|
||||
private String desc;
|
||||
@@ -38,10 +38,11 @@ public enum CurrentDesignPictureTypeEnum {
|
||||
this.desc = desc;
|
||||
}
|
||||
|
||||
public static CurrentDesignPictureTypeEnum of(String name){
|
||||
return Stream.of(CurrentDesignPictureTypeEnum.values()).filter(v ->v.name().equals(name)).findFirst().orElse(null);
|
||||
public static CurrentDesignPictureTypeEnum of(String name) {
|
||||
return Stream.of(CurrentDesignPictureTypeEnum.values()).filter(v -> v.name().equals(name)).findFirst().orElse(null);
|
||||
}
|
||||
public static List<CurrentDesignPictureTypeEnum> ofList(List<Integer> codes){
|
||||
return Stream.of(CurrentDesignPictureTypeEnum.values()).filter(v ->codes.contains(v.code)).collect(Collectors.toList());
|
||||
|
||||
public static List<CurrentDesignPictureTypeEnum> ofList(List<Integer> codes) {
|
||||
return Stream.of(CurrentDesignPictureTypeEnum.values()).filter(v -> codes.contains(v.code)).collect(Collectors.toList());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -16,15 +16,15 @@ public enum CurrentDesignPrintPictureTypeEnum {
|
||||
/**
|
||||
* 空白
|
||||
*/
|
||||
NO(1,"空白"),
|
||||
NO(1, "空白"),
|
||||
/**
|
||||
* PIN
|
||||
*/
|
||||
PIN(2,"PIN"),
|
||||
PIN(2, "PIN"),
|
||||
/**
|
||||
* noPIN
|
||||
*/
|
||||
NO_PIN(3,"noPIN");
|
||||
NO_PIN(3, "noPIN");
|
||||
|
||||
private Integer code;
|
||||
private String desc;
|
||||
@@ -33,7 +33,8 @@ public enum CurrentDesignPrintPictureTypeEnum {
|
||||
this.code = code;
|
||||
this.desc = desc;
|
||||
}
|
||||
public static List<CurrentDesignPrintPictureTypeEnum> ofList(List<Integer> codes){
|
||||
return Stream.of(CurrentDesignPrintPictureTypeEnum.values()).filter(v ->codes.contains(v.code)).collect(Collectors.toList());
|
||||
|
||||
public static List<CurrentDesignPrintPictureTypeEnum> ofList(List<Integer> codes) {
|
||||
return Stream.of(CurrentDesignPrintPictureTypeEnum.values()).filter(v -> codes.contains(v.code)).collect(Collectors.toList());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -15,7 +15,8 @@ public enum DesignTypeEnum {
|
||||
/**
|
||||
* Library
|
||||
*/
|
||||
LIBRARY("Library");
|
||||
LIBRARY("Library"),
|
||||
GENERATE("Generate");
|
||||
|
||||
private String realName;
|
||||
|
||||
|
||||
34
src/main/java/com/ai/da/common/enums/FluxTaskStatusEnum.java
Normal file
34
src/main/java/com/ai/da/common/enums/FluxTaskStatusEnum.java
Normal file
@@ -0,0 +1,34 @@
|
||||
package com.ai.da.common.enums;
|
||||
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Getter;
|
||||
|
||||
@AllArgsConstructor
|
||||
@Getter
|
||||
public enum FluxTaskStatusEnum {
|
||||
|
||||
SUCCESS("Ready"),
|
||||
|
||||
TASK_NOT_FOUND("Task not found"),
|
||||
|
||||
REQUEST_MODERATED("Request Moderated"),
|
||||
|
||||
CONTENT_MODERATED("Content Moderated"),
|
||||
|
||||
ERROR("Error"),
|
||||
|
||||
PENDING_F("Pending");
|
||||
|
||||
private final String name;
|
||||
|
||||
public static FluxTaskStatusEnum fromName(String name) {
|
||||
for (FluxTaskStatusEnum status : values()) {
|
||||
if (status.name.equalsIgnoreCase(name)) {
|
||||
return status;
|
||||
}
|
||||
}
|
||||
// 或者返回默认值
|
||||
return TASK_NOT_FOUND;
|
||||
}
|
||||
}
|
||||
45
src/main/java/com/ai/da/common/enums/GenerateModeEnum.java
Normal file
45
src/main/java/com/ai/da/common/enums/GenerateModeEnum.java
Normal file
@@ -0,0 +1,45 @@
|
||||
package com.ai.da.common.enums;
|
||||
|
||||
import lombok.Getter;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
@Getter
|
||||
public enum GenerateModeEnum {
|
||||
|
||||
/**
|
||||
* 通过文本生成
|
||||
*/
|
||||
TEXT(1, "text","txt2img"),
|
||||
|
||||
/**
|
||||
* 通过图片生成
|
||||
*/
|
||||
IMAGE(2, "image", "img2img"),
|
||||
|
||||
/**
|
||||
* 通过文本和图片生成
|
||||
*/
|
||||
TEXT_IMAGE(2, "text-image","img2img");
|
||||
|
||||
private Integer code;
|
||||
private String value;
|
||||
private String type;
|
||||
|
||||
GenerateModeEnum(int code, String value) {
|
||||
this.code = code;
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
GenerateModeEnum(Integer code, String value, String type) {
|
||||
this.code = code;
|
||||
this.value = value;
|
||||
this.type = type;
|
||||
}
|
||||
|
||||
public static List<String> getGenerateModeList(){
|
||||
return Stream.of(TEXT,IMAGE,TEXT_IMAGE).map(GenerateModeEnum::getValue).collect(Collectors.toList());
|
||||
}
|
||||
}
|
||||
56
src/main/java/com/ai/da/common/enums/LayersPriorityEnum.java
Normal file
56
src/main/java/com/ai/da/common/enums/LayersPriorityEnum.java
Normal file
@@ -0,0 +1,56 @@
|
||||
package com.ai.da.common.enums;
|
||||
|
||||
import lombok.Getter;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
public enum LayersPriorityEnum {
|
||||
|
||||
EARRING_FRONT("earring_front","Earring",99),
|
||||
BAG_FRONT("bag_front","Bag",98),
|
||||
HAIRSTYLE_FRONT("hairstyle_front","Hairstyle",97),
|
||||
OUTWEAR_FRONT("outwear_front","Outwear",20),
|
||||
TOPS_FRONT("tops_front","Tops",19),
|
||||
DRESS_FRONT("dress_front","Dress",18),
|
||||
BLOUSE_FRONT("blouse_front","Blouse",17),
|
||||
SKIRT_FRONT("skirt_front","Skirt",16),
|
||||
TROUSERS_FRONT("trousers_front","Trousers",15),
|
||||
BOTTOMS_FRONT("bottoms_front","Bottoms",14),
|
||||
SHOES_RIGHT("shoes_right","Shoes",1),
|
||||
SHOES_LEFT("shoes_left","Shoes",1),
|
||||
BODY("body","Body",0),
|
||||
BOTTOMS_BACK("bottoms_back","Bottoms",-14),
|
||||
TROUSERS_BACK("trousers_back","Trousers",-15),
|
||||
SKIRT_BACK("skirt_back","Skirt",-16),
|
||||
BLOUSE_BACK("blouse_back","Blouse",-17),
|
||||
DRESS_BACK("dress_back","Dress",-18),
|
||||
TOPS_BACK("tops_back","Tops",-19),
|
||||
OUTWEAR_BACK("outwear_back","Outwear",-20),
|
||||
HAIRSTYLE_BACK("hairstyle_back","Hairstyle",-97),
|
||||
BAG_BACK("bag_back","Bag",-98),
|
||||
EARRING_BACK("earring_back","Earring",-99);
|
||||
|
||||
@Getter
|
||||
private String realName;
|
||||
@Getter
|
||||
private String type;
|
||||
@Getter
|
||||
private Integer value;
|
||||
|
||||
|
||||
LayersPriorityEnum(String realName, String type,Integer value) {
|
||||
this.realName = realName;
|
||||
this.type = type;
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
public static LayersPriorityEnum getValueByType(String type){
|
||||
return Stream.of(LayersPriorityEnum.values()).filter(l -> l.getType().equals(type)).findFirst().orElse(null);
|
||||
}
|
||||
|
||||
public static LayersPriorityEnum getValueByLayerCategory(String layerCategory){
|
||||
return Stream.of(LayersPriorityEnum.values()).filter(l -> l.getRealName().equals(layerCategory)).findFirst().orElse(null);
|
||||
}
|
||||
}
|
||||
@@ -27,7 +27,10 @@ public enum LibraryLevel1TypeEnum {
|
||||
/**
|
||||
* 模特
|
||||
*/
|
||||
MODELS("Models");
|
||||
MODELS("Models"),
|
||||
DESIGN_ELEMENTS("DesignElements"),
|
||||
|
||||
BRAND_DNA("BrandDNA");
|
||||
|
||||
private String realName;
|
||||
|
||||
@@ -39,8 +42,8 @@ public enum LibraryLevel1TypeEnum {
|
||||
return realName;
|
||||
}
|
||||
|
||||
public static LibraryLevel1TypeEnum uploadOf(String realName){
|
||||
public static LibraryLevel1TypeEnum uploadOf(String realName) {
|
||||
return Stream.of(LibraryLevel1TypeEnum.values())
|
||||
.filter(v ->v.getRealName().equals(realName)).findFirst().orElse(null);
|
||||
.filter(v -> v.getRealName().equals(realName)).findFirst().orElse(null);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -30,9 +30,10 @@ public enum LibraryTopTypeEnum {
|
||||
public String getRealName() {
|
||||
return realName;
|
||||
}
|
||||
public static LibraryTopTypeEnum uploadOf(String realName){
|
||||
|
||||
public static LibraryTopTypeEnum uploadOf(String realName) {
|
||||
return Stream.of(LibraryTopTypeEnum.values())
|
||||
.filter(v ->v.getRealName().equals(realName)).findFirst().orElse(null);
|
||||
.filter(v -> v.getRealName().equals(realName)).findFirst().orElse(null);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -17,7 +17,7 @@ public enum LoginTypeEnum {
|
||||
*/
|
||||
PASSWORD;
|
||||
|
||||
public static LoginTypeEnum of(String name){
|
||||
return Stream.of(LoginTypeEnum.values()).filter(v ->v.name().equals(name)).findFirst().orElse(null);
|
||||
public static LoginTypeEnum of(String name) {
|
||||
return Stream.of(LoginTypeEnum.values()).filter(v -> v.name().equals(name)).findFirst().orElse(null);
|
||||
}
|
||||
}
|
||||
|
||||
22
src/main/java/com/ai/da/common/enums/ModelNameEnum.java
Normal file
22
src/main/java/com/ai/da/common/enums/ModelNameEnum.java
Normal file
@@ -0,0 +1,22 @@
|
||||
package com.ai.da.common.enums;
|
||||
|
||||
import lombok.Getter;
|
||||
|
||||
@Getter
|
||||
public enum ModelNameEnum {
|
||||
|
||||
/**
|
||||
* 使用模型0
|
||||
*/
|
||||
MODEL_0("0", "model_0");
|
||||
|
||||
|
||||
private String code;
|
||||
private String modelName;
|
||||
|
||||
|
||||
ModelNameEnum(String code, String modelName) {
|
||||
this.code = code;
|
||||
this.modelName = modelName;
|
||||
}
|
||||
}
|
||||
29
src/main/java/com/ai/da/common/enums/MotionModeEnum.java
Normal file
29
src/main/java/com/ai/da/common/enums/MotionModeEnum.java
Normal file
@@ -0,0 +1,29 @@
|
||||
package com.ai.da.common.enums;
|
||||
|
||||
|
||||
import lombok.Getter;
|
||||
|
||||
import java.util.stream.Stream;
|
||||
|
||||
@Getter
|
||||
public enum MotionModeEnum {
|
||||
POSE_TO_VIDEO(1, "/api/comfyui_image_pose_2_video"),
|
||||
|
||||
PROMPT_TO_VIDEO(2, "/api/comfyui_image_2_video"),
|
||||
|
||||
FIRST_LAST_FRAME_TO_VIDEO(3, "/api/comfyui_flf_2_video")
|
||||
;
|
||||
|
||||
private int code;
|
||||
|
||||
private String url;
|
||||
|
||||
MotionModeEnum(int code, String url) {
|
||||
this.code = code;
|
||||
this.url = url;
|
||||
}
|
||||
|
||||
public static MotionModeEnum of(int code) {
|
||||
return Stream.of(MotionModeEnum.values()).filter(v -> v.getCode()== code).findFirst().orElse(null);
|
||||
}
|
||||
}
|
||||
@@ -1,31 +0,0 @@
|
||||
package com.ai.da.common.enums;
|
||||
|
||||
import java.util.stream.Stream;
|
||||
|
||||
/**
|
||||
* @author: yanglei
|
||||
* @description: 操作类型 登入 忘记密码
|
||||
* @create: 2022-8-10 17:33
|
||||
**/
|
||||
public enum OperationTypeEnum {
|
||||
/**
|
||||
*登入
|
||||
*/
|
||||
LOGIN,
|
||||
/**
|
||||
* 异常ip
|
||||
*/
|
||||
EXCEPTION_IP,
|
||||
/**
|
||||
* 绑定邮箱
|
||||
*/
|
||||
BIND_MAILBOX,
|
||||
/**
|
||||
* 忘记密码
|
||||
*/
|
||||
FORGET_PWD;
|
||||
|
||||
public static OperationTypeEnum of(String name){
|
||||
return Stream.of(OperationTypeEnum.values()).filter(v ->v.name().equals(name)).findFirst().orElse(null);
|
||||
}
|
||||
}
|
||||
50
src/main/java/com/ai/da/common/enums/OrderStatusEnum.java
Normal file
50
src/main/java/com/ai/da/common/enums/OrderStatusEnum.java
Normal file
@@ -0,0 +1,50 @@
|
||||
package com.ai.da.common.enums;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Getter;
|
||||
|
||||
@AllArgsConstructor
|
||||
@Getter
|
||||
public enum OrderStatusEnum {
|
||||
/**
|
||||
* 未支付
|
||||
*/
|
||||
NOT_PAY("未支付"),
|
||||
/**
|
||||
* 支付成功
|
||||
*/
|
||||
SUCCESS("支付成功"),
|
||||
/**
|
||||
* 支付失败
|
||||
*/
|
||||
FAILURE("支付失败"),
|
||||
/**
|
||||
* 已关闭
|
||||
*/
|
||||
TIMEOUT_CLOSED("超时已关闭"),
|
||||
/**
|
||||
* 已取消
|
||||
*/
|
||||
CANCEL("用户已取消"),
|
||||
/**
|
||||
* 退款中
|
||||
*/
|
||||
REFUND_PROCESSING("退款中"),
|
||||
/**
|
||||
* 已退款
|
||||
*/
|
||||
REFUND_SUCCESS("已退款"),
|
||||
/**
|
||||
* 退款异常
|
||||
*/
|
||||
REFUND_ABNORMAL("退款异常"),
|
||||
/**
|
||||
* paypal订单状态为 APPROVED
|
||||
*/
|
||||
ORDER_PROCESSING("订单处理中");
|
||||
|
||||
/**
|
||||
* 类型
|
||||
*/
|
||||
private final String type;
|
||||
}
|
||||
@@ -6,5 +6,5 @@ package com.ai.da.common.enums;
|
||||
* @create: 2020-01-14 17:33
|
||||
**/
|
||||
public enum OrderType {
|
||||
DESC,ASC;
|
||||
DESC, ASC;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,30 @@
|
||||
package com.ai.da.common.enums;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Getter;
|
||||
|
||||
@Getter
|
||||
@AllArgsConstructor
|
||||
public enum PayPalOrderStatusEnum {
|
||||
|
||||
// The order was created with the specified context.
|
||||
// 订单已创建并具有指定的上下文。
|
||||
CREATED("CREATED"),
|
||||
// The order was saved and persisted. The order status continues to be in progress until a capture is made with final_capture = true for all purchase units within the order.
|
||||
// 订单已保存并持久化。订单状态仍处于进行中,直到对订单中的所有购买单元进行了 final_capture = true 的捕获为止
|
||||
SAVED("SAVED"),
|
||||
// The customer approved the payment through the PayPal wallet or another form of guest or unbranded payment. For example, a card, bank account, or so on.
|
||||
// 客户通过PayPal钱包或其他形式的游客或非品牌支付批准了付款。例如,信用卡、银行账户等。
|
||||
APPROVED("APPROVED"),
|
||||
// All purchase units in the order are voided.
|
||||
// 订单中的所有购买单元都已作废。
|
||||
VOIDED("VOIDED"),
|
||||
// The payment was authorized or the authorized payment was captured for the order.
|
||||
// 订单的支付已被授权或已捕获授权的支付。
|
||||
COMPLETED("COMPLETED"),
|
||||
// The order requires an action from the payer (e.g. 3DS authentication). Redirect the payer to the "rel":"payer-action" HATEOAS link returned as part of the response prior to authorizing or capturing the order.
|
||||
// 订单需要支付者执行某项操作(例如3DS身份验证)。在授权或捕获订单之前,请将支付者重定向到响应中返回的"rel":"payer-action" HATEOAS链接。
|
||||
PAYER_ACTION_REQUIRED("PAYER_ACTION_REQUIRED");
|
||||
|
||||
private final String status;
|
||||
}
|
||||
38
src/main/java/com/ai/da/common/enums/PayTypeEnum.java
Normal file
38
src/main/java/com/ai/da/common/enums/PayTypeEnum.java
Normal file
@@ -0,0 +1,38 @@
|
||||
package com.ai.da.common.enums;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Getter;
|
||||
|
||||
@AllArgsConstructor
|
||||
@Getter
|
||||
public enum PayTypeEnum {
|
||||
/**
|
||||
* 微信
|
||||
*/
|
||||
WXPAY("微信"),
|
||||
|
||||
/**
|
||||
* 支付宝
|
||||
*/
|
||||
ALIPAY("支付宝"),
|
||||
|
||||
/**
|
||||
* PayPal
|
||||
*/
|
||||
PAYPAL("PayPal"),
|
||||
|
||||
/**
|
||||
* 香港支付宝
|
||||
*/
|
||||
ALIPAY_HK("Alipay-HK"),
|
||||
|
||||
/**
|
||||
* Stripe
|
||||
*/
|
||||
STRIPE("Stripe");
|
||||
|
||||
/**
|
||||
* 类型
|
||||
*/
|
||||
private final String type;
|
||||
}
|
||||
81
src/main/java/com/ai/da/common/enums/PoseEnum.java
Normal file
81
src/main/java/com/ai/da/common/enums/PoseEnum.java
Normal file
@@ -0,0 +1,81 @@
|
||||
package com.ai.da.common.enums;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Getter;
|
||||
|
||||
import java.util.*;
|
||||
import java.util.function.Function;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
@AllArgsConstructor
|
||||
@Getter
|
||||
public enum PoseEnum {
|
||||
|
||||
// POSE_1(1, "aida-sys-image/pose/pose-1.mp4", "aida-sys-image/pose/pose-1.gif", "aida-sys-image/pose/pose-1-first_frame.jpeg", "AACT.8090e67b.-E3pujumEfCbDTI_rjSH-A.LwIlGT3j"),
|
||||
POSE_1(1, "aida-sys-image/pose/pose-1-1.mp4", "aida-sys-image/pose/pose-1-1.gif", "aida-sys-image/pose/pose-1-first_frame.jpeg", "AACT.8090e67b.qNMWJlyKEfCuORaRJeW4dg.x3wUteVO"),
|
||||
// POSE_2(2, "aida-sys-image/pose/pose-2.mp4", "aida-sys-image/pose/pose-2.gif", "aida-sys-image/pose/pose-2-first_frame.jpeg", "AACT.8090e67b.TwJLxEv3EfCbDTI_rjSH-A.IOQZCYhf"),
|
||||
POSE_2(2, "aida-sys-image/pose/pose-2-1.mp4", "aida-sys-image/pose/pose-2-1.gif", "aida-sys-image/pose/pose-2-first_frame.jpeg", "AACT.8090e67b.QpaGOlyLEfCuuJo8eQGF2Q.62EiJj-6"),
|
||||
// POSE_3(3, "aida-sys-image/pose/pose-3.mp4", "aida-sys-image/pose/pose-3.gif", "aida-sys-image/pose/pose-3-first_frame.jpeg", "AACT.8090e67b.gd3OCkv4EfCxyZo8eQGF2Q.qMm-a1XI"),
|
||||
POSE_3(3, "aida-sys-image/pose/pose-3-1.mp4", "aida-sys-image/pose/pose-3-1.gif", "aida-sys-image/pose/pose-3-first_frame.jpeg", "AACT.8090e67b.2q5qjFyLEfCImjI_rjSH-A.5cFMwOvi"),
|
||||
// POSE_4(4, "aida-sys-image/pose/pose-4.mp4", "aida-sys-image/pose/pose-4.gif", "aida-sys-image/pose/pose-4-first_frame.jpeg", "AACT.8090e67b.AUDnuEwDEfCEHBaRJeW4dg.rlx36xEY"),
|
||||
POSE_4(4, "aida-sys-image/pose/pose-4-1.mp4", "aida-sys-image/pose/pose-4-1.gif", "aida-sys-image/pose/pose-4-first_frame.jpeg", "AACT.8090e67b.KoYMplyPEfCuORaRJeW4dg.MuuBTG78"),
|
||||
// POSE_5(5, "aida-sys-image/pose/pose-5.mp4", "aida-sys-image/pose/pose-5.gif", "aida-sys-image/pose/pose-5-first_frame.jpeg", "AACT.8090e67b.G8BvkEwEEfCxyZo8eQGF2Q.fo4ryrgR"),
|
||||
POSE_5(5, "aida-sys-image/pose/pose-5-1.mp4", "aida-sys-image/pose/pose-5-1.gif", "aida-sys-image/pose/pose-5-first_frame.jpeg", "AACT.8090e67b.x54FNFyPEfCuuJo8eQGF2Q.P1egmEZ_"),
|
||||
// POSE_6(6, "aida-sys-image/pose/pose-6.mp4", "aida-sys-image/pose/pose-6.gif", "aida-sys-image/pose/pose-6-first_frame.jpeg", "AACT.8090e67b.yBIPnEwEEfCxyZo8eQGF2Q.boSFwTG9");
|
||||
POSE_6(6, "aida-sys-image/pose/pose-6-1.mp4", "aida-sys-image/pose/pose-6-1.gif", "aida-sys-image/pose/pose-6-first_frame.jpeg", "AACT.8090e67b.QSCvBlyQEfCImjI_rjSH-A.G9-Z5ffW");
|
||||
|
||||
|
||||
private final Integer id;
|
||||
|
||||
private final String videoPath;
|
||||
|
||||
private final String gifPath;
|
||||
|
||||
private final String firstFramePath;
|
||||
|
||||
private final String templateId;
|
||||
|
||||
private static final List<Map<String, String>> PROPERTY_LIST;
|
||||
|
||||
static {
|
||||
PROPERTY_LIST = Arrays.stream(values())
|
||||
.map(PoseEnum::toMap)
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
|
||||
private static final Map<Integer, PoseEnum> BY_ID = Arrays.stream(values())
|
||||
.collect(Collectors.toMap(PoseEnum::getId, Function.identity()));
|
||||
|
||||
private static final Map<String, PoseEnum> BY_VIDEO_PATH = Arrays.stream(values())
|
||||
.collect(Collectors.toMap(PoseEnum::getVideoPath, Function.identity()));
|
||||
|
||||
private static final List<String> VIDEO_PATH = Arrays.stream(values())
|
||||
.map(PoseEnum::getVideoPath).collect(Collectors.toList());
|
||||
|
||||
public static PoseEnum getById(Integer id) {
|
||||
return BY_ID.get(id);
|
||||
}
|
||||
|
||||
public static PoseEnum getByVideoPath(String videoPath) {
|
||||
return BY_VIDEO_PATH.get(videoPath);
|
||||
}
|
||||
|
||||
private Map<String, String> toMap() {
|
||||
Map<String, String> map = new HashMap<>();
|
||||
map.put("id", String.valueOf(id));
|
||||
map.put("gif", gifPath);
|
||||
map.put("video", videoPath);
|
||||
map.put("firstFrame", firstFramePath);
|
||||
return map;
|
||||
}
|
||||
|
||||
public static List<Map<String, String>> getPropertyList() {
|
||||
return PROPERTY_LIST.stream()
|
||||
.map(HashMap::new) // 深拷贝每个 Map
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
|
||||
public static List<String> getVideoList() {
|
||||
return new ArrayList<>(VIDEO_PATH); // 返回副本以保证不可变性
|
||||
}
|
||||
}
|
||||
33
src/main/java/com/ai/da/common/enums/ProductEnum.java
Normal file
33
src/main/java/com/ai/da/common/enums/ProductEnum.java
Normal file
@@ -0,0 +1,33 @@
|
||||
package com.ai.da.common.enums;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Getter;
|
||||
|
||||
@Getter
|
||||
@AllArgsConstructor
|
||||
public enum ProductEnum {
|
||||
// 积分购买
|
||||
CreditsProduct("AiDA credits purchase", 10L, 50L),
|
||||
// 年度订阅
|
||||
AnnualSubscription("AiDA Annual Subscription", 5000L, 50000L),
|
||||
// 月度订阅(订阅费500,每月3500 积分)
|
||||
MonthlySubscription("AiDA Monthly Subscription", 500L, 3500L),
|
||||
// 月度订阅 -- 经济实惠版 (订阅费100,每月500 积分)
|
||||
Eco_MonthlySubscription("AiDA Eco Monthly Subscription", 100L, 500L),
|
||||
// 季度订阅
|
||||
QuarterlySubscription("AiDA Quarterly Subscription", 1500L, 12000L),
|
||||
// 月度订阅 -- 教育版
|
||||
EDUMonthlySubscription("AiDA Edu Monthly Subscription", 200L, 3500L),
|
||||
// 测试
|
||||
DailySubscription("AiDA Daily Subscription", 5L, 100L),
|
||||
;
|
||||
|
||||
/**
|
||||
* 类型
|
||||
*/
|
||||
private final String name;
|
||||
|
||||
private final Long price;
|
||||
|
||||
private final Long credits;
|
||||
}
|
||||
@@ -4,7 +4,7 @@ import java.util.stream.Stream;
|
||||
|
||||
/**
|
||||
* @author yanglei
|
||||
* @description python调用java 操作数类型 generatePrint ->生成印花 designCollection ->设计collection
|
||||
* @description python调用java 操作数类型 generatePrint ->生成印花 designCollection ->设计collection generateSketch->设计草图
|
||||
* @create 2022-10-3 17:33
|
||||
**/
|
||||
public enum PythonToJavaApiOperationTypeEnum {
|
||||
@@ -19,7 +19,12 @@ public enum PythonToJavaApiOperationTypeEnum {
|
||||
/**
|
||||
* 设计collection
|
||||
*/
|
||||
DESIGN_COLLECTION("designCollection");
|
||||
DESIGN_COLLECTION("designCollection"),
|
||||
|
||||
/**
|
||||
* 生成草图
|
||||
*/
|
||||
GENERATE_SKETCH("generateSketch");
|
||||
|
||||
private String realName;
|
||||
|
||||
@@ -31,7 +36,7 @@ public enum PythonToJavaApiOperationTypeEnum {
|
||||
return realName;
|
||||
}
|
||||
|
||||
public static PythonToJavaApiOperationTypeEnum uploadOf(String realName){
|
||||
return Stream.of(PythonToJavaApiOperationTypeEnum.values()).filter(v ->v.getRealName().equals(realName)).findFirst().orElse(null);
|
||||
public static PythonToJavaApiOperationTypeEnum uploadOf(String realName) {
|
||||
return Stream.of(PythonToJavaApiOperationTypeEnum.values()).filter(v -> v.getRealName().equals(realName)).findFirst().orElse(null);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -27,7 +27,7 @@ public enum SingleOverallEnum {
|
||||
return realName;
|
||||
}
|
||||
|
||||
public static SingleOverallEnum of(String realName){
|
||||
return Stream.of(SingleOverallEnum.values()).filter(v ->v.getRealName().equals(realName)).findFirst().orElse(null);
|
||||
public static SingleOverallEnum of(String realName) {
|
||||
return Stream.of(SingleOverallEnum.values()).filter(v -> v.getRealName().equals(realName)).findFirst().orElse(null);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -28,6 +28,8 @@ public enum SwitchCategoryEnum {
|
||||
* 裤子
|
||||
*/
|
||||
TROUSERS("Trousers"),
|
||||
TOPS("Tops"),
|
||||
BOTTOMS("Bottoms"),
|
||||
;
|
||||
|
||||
private String realName;
|
||||
@@ -40,7 +42,7 @@ public enum SwitchCategoryEnum {
|
||||
return realName;
|
||||
}
|
||||
|
||||
public static SwitchCategoryEnum of(String realName){
|
||||
return Stream.of(SwitchCategoryEnum.values()).filter(v ->v.getRealName().equals(realName)).findFirst().orElse(null);
|
||||
public static SwitchCategoryEnum of(String realName) {
|
||||
return Stream.of(SwitchCategoryEnum.values()).filter(v -> v.getRealName().equals(realName)).findFirst().orElse(null);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -9,11 +9,11 @@ import java.util.stream.Stream;
|
||||
**/
|
||||
public enum SysFileLevel1TypeEnum {
|
||||
|
||||
IMAGES("Images","images"),
|
||||
IMAGES("Images", "images"),
|
||||
|
||||
ICON_C("Iconc","iconc"),
|
||||
ICON_C("Iconc", "iconc"),
|
||||
|
||||
ACCESSORIES("Accessories","accessories");
|
||||
ACCESSORIES("Accessories", "accessories");
|
||||
|
||||
private String realName;
|
||||
/**
|
||||
@@ -34,7 +34,7 @@ public enum SysFileLevel1TypeEnum {
|
||||
return uploadPathName;
|
||||
}
|
||||
|
||||
public static SysFileLevel1TypeEnum uploadOf(String uploadPathName){
|
||||
return Stream.of(SysFileLevel1TypeEnum.values()).filter(v ->v.getUploadPathName().equals(uploadPathName)).findFirst().orElse(null);
|
||||
public static SysFileLevel1TypeEnum uploadOf(String uploadPathName) {
|
||||
return Stream.of(SysFileLevel1TypeEnum.values()).filter(v -> v.getUploadPathName().equals(uploadPathName)).findFirst().orElse(null);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
package com.ai.da.common.enums;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.stream.Stream;
|
||||
@@ -13,27 +14,27 @@ public enum SysFileLevel2TypeEnum {
|
||||
/**
|
||||
* ICON
|
||||
*/
|
||||
ICON("Icon","icon"),
|
||||
ICON("Icon", "icon"),
|
||||
|
||||
BAG("Bag","bag"),
|
||||
BAG("Bag", "bag"),
|
||||
|
||||
EARRINGS("Earring","earring"),
|
||||
EARRINGS("Earring", "earring"),
|
||||
|
||||
HAIRSTYLE("Hairstyle","hairstyle"),
|
||||
HAIRSTYLE("Hairstyle", "hairstyle"),
|
||||
|
||||
SHOES("Shoes","shoes"),
|
||||
SHOES("Shoes", "shoes"),
|
||||
|
||||
BODY("Body","body"),
|
||||
BODY("Body", "body"),
|
||||
|
||||
BLOUSE("Blouse","blouse"),
|
||||
BLOUSE("Blouse", "blouse"),
|
||||
|
||||
DRESS("Dress","dress"),
|
||||
DRESS("Dress", "dress"),
|
||||
|
||||
OUTWEAR("Outwear","outwear"),
|
||||
OUTWEAR("Outwear", "outwear"),
|
||||
|
||||
SKIRT("Skirt","skirt"),
|
||||
SKIRT("Skirt", "skirt"),
|
||||
|
||||
TROUSERS("Trousers","trousers");
|
||||
TROUSERS("Trousers", "trousers");
|
||||
|
||||
private String realName;
|
||||
/**
|
||||
@@ -54,20 +55,40 @@ public enum SysFileLevel2TypeEnum {
|
||||
return uploadPathName;
|
||||
}
|
||||
|
||||
public static SysFileLevel2TypeEnum uploadOf(String uploadPathName){
|
||||
return Stream.of(SysFileLevel2TypeEnum.values()).filter(v ->v.getUploadPathName().equals(uploadPathName)).findFirst().orElse(null);
|
||||
}
|
||||
public static SysFileLevel2TypeEnum realNameOf(String realName){
|
||||
return Stream.of(SysFileLevel2TypeEnum.values()).filter(v ->v.getRealName().equals(realName)).findFirst().orElse(null);
|
||||
public static SysFileLevel2TypeEnum uploadOf(String uploadPathName) {
|
||||
return Stream.of(SysFileLevel2TypeEnum.values()).filter(v -> v.getUploadPathName().equals(uploadPathName)).findFirst().orElse(null);
|
||||
}
|
||||
|
||||
public static SysFileLevel2TypeEnum realNameOfPython(String realName){
|
||||
return Stream.of(BLOUSE,DRESS,OUTWEAR,SKIRT,TROUSERS).filter(v ->v.getRealName().equals(realName)).findFirst().orElse(null);
|
||||
public static SysFileLevel2TypeEnum realNameOf(String realName) {
|
||||
return Stream.of(SysFileLevel2TypeEnum.values()).filter(v -> v.getRealName().equals(realName)).findFirst().orElse(null);
|
||||
}
|
||||
public static List<String> ofPython(){
|
||||
return Stream.of(BLOUSE,DRESS,OUTWEAR,SKIRT,TROUSERS).map(SysFileLevel2TypeEnum::getRealName).collect(Collectors.toList());
|
||||
|
||||
public static SysFileLevel2TypeEnum realNameOfPython(String realName) {
|
||||
return Stream.of(BLOUSE, DRESS, OUTWEAR, SKIRT, TROUSERS).filter(v -> v.getRealName().equals(realName)).findFirst().orElse(null);
|
||||
}
|
||||
public static List<String> ofPythonPath(){
|
||||
return Stream.of(BLOUSE,DRESS,OUTWEAR,SKIRT,TROUSERS).map(SysFileLevel2TypeEnum::getUploadPathName).collect(Collectors.toList());
|
||||
|
||||
public static List<String> ofPython() {
|
||||
return Stream.of(BLOUSE, DRESS, OUTWEAR, SKIRT, TROUSERS).map(SysFileLevel2TypeEnum::getRealName).collect(Collectors.toList());
|
||||
}
|
||||
|
||||
public static List<String> ofPythonPath() {
|
||||
return Stream.of(BLOUSE, DRESS, OUTWEAR, SKIRT, TROUSERS).map(SysFileLevel2TypeEnum::getUploadPathName).collect(Collectors.toList());
|
||||
}
|
||||
|
||||
public static final List<String> ACCESSORIES_LIST = Arrays.asList(
|
||||
SysFileLevel2TypeEnum.BAG.getRealName(),
|
||||
SysFileLevel2TypeEnum.EARRINGS.getRealName(),
|
||||
SysFileLevel2TypeEnum.HAIRSTYLE.getRealName(),
|
||||
SysFileLevel2TypeEnum.SHOES.getRealName(),
|
||||
SysFileLevel2TypeEnum.BODY.getRealName()
|
||||
);
|
||||
|
||||
public static final List<String> IMAGES_LIST = Arrays.asList(
|
||||
SysFileLevel2TypeEnum.BLOUSE.getRealName(),
|
||||
SysFileLevel2TypeEnum.DRESS.getRealName(),
|
||||
SysFileLevel2TypeEnum.OUTWEAR.getRealName(),
|
||||
SysFileLevel2TypeEnum.SKIRT.getRealName(),
|
||||
SysFileLevel2TypeEnum.TROUSERS.getRealName()
|
||||
);
|
||||
|
||||
}
|
||||
|
||||
@@ -0,0 +1,32 @@
|
||||
package com.ai.da.common.enums;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Getter;
|
||||
|
||||
@AllArgsConstructor
|
||||
@Getter
|
||||
public enum WangXiangTaskStatusEnum {
|
||||
|
||||
SUCCEEDED("SUCCEEDED"),
|
||||
|
||||
UNKNOWN_W("UNKNOWN"),
|
||||
|
||||
FAILED("FAILED"),
|
||||
|
||||
RUNNING("RUNNING"),
|
||||
|
||||
PENDING_W("PENDING");
|
||||
|
||||
private final String name;
|
||||
|
||||
// 通过name查找枚举的静态方法
|
||||
public static WangXiangTaskStatusEnum fromName(String name) {
|
||||
for (WangXiangTaskStatusEnum status : values()) {
|
||||
if (status.name.equalsIgnoreCase(name)) {
|
||||
return status;
|
||||
}
|
||||
}
|
||||
// 或者返回默认值
|
||||
return UNKNOWN_W;
|
||||
}
|
||||
}
|
||||
@@ -16,23 +16,24 @@ public class TokenQuery {
|
||||
private static final String GENERATE_USER_DOMAIN = "https://www.szsige.com";
|
||||
|
||||
public static JSONObject getToken(String session) {
|
||||
String url = GET_TOKEN_DOMAIN + TokenApis.GET_TOKEN.getUrl()+ session;
|
||||
String url = GET_TOKEN_DOMAIN + TokenApis.GET_TOKEN.getUrl() + session;
|
||||
log.info("获取用户token接口请求url:" + url);
|
||||
HttpResponse httpResponse = HttpUtil.createPost(url).execute();
|
||||
log.info("获取用户token接口响应:" + httpResponse);
|
||||
if(httpResponse.isOk() && StrUtil.isNotEmpty(httpResponse.body())){
|
||||
if (httpResponse.isOk() && StrUtil.isNotEmpty(httpResponse.body())) {
|
||||
return JSONObject.parseObject(httpResponse.body());
|
||||
}
|
||||
return null;
|
||||
}
|
||||
public static JSONObject generateUser(Map<String, Object> param,String token) {
|
||||
|
||||
public static JSONObject generateUser(Map<String, Object> param, String token) {
|
||||
HttpResponse httpResponse = HttpUtil.createPost(GENERATE_USER_DOMAIN + TokenApis.GENERATE_USER.getUrl())
|
||||
.body(JSONObject.toJSONString(param!=null?param:new HashMap<>()))
|
||||
.header("Authorization", "Bearer "+token)
|
||||
.body(JSONObject.toJSONString(param != null ? param : new HashMap<>()))
|
||||
.header("Authorization", "Bearer " + token)
|
||||
.header("X-Promiss", "9672233956")
|
||||
.execute();
|
||||
log.info("生成用户信息接口响应:" + httpResponse);
|
||||
if(httpResponse.isOk() && StrUtil.isNotEmpty(httpResponse.body())){
|
||||
if (httpResponse.isOk() && StrUtil.isNotEmpty(httpResponse.body())) {
|
||||
return JSONObject.parseObject(httpResponse.body());
|
||||
}
|
||||
return null;
|
||||
|
||||
@@ -1,8 +1,7 @@
|
||||
package com.ai.da.common.response;
|
||||
|
||||
import com.baomidou.mybatisplus.core.metadata.IPage;
|
||||
import io.swagger.annotations.ApiModel;
|
||||
import io.swagger.annotations.ApiModelProperty;
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
@@ -16,21 +15,20 @@ import java.util.List;
|
||||
*/
|
||||
@Data
|
||||
@NoArgsConstructor
|
||||
@ApiModel("分页响应结果")
|
||||
public class PageBaseResponse<T>{
|
||||
@ApiModelProperty("页码")
|
||||
@Schema(description = "分页响应结果")
|
||||
public class PageBaseResponse<T> {
|
||||
@Schema(description = "页码")
|
||||
private long page;
|
||||
@ApiModelProperty("每页数量")
|
||||
@Schema(description = "每页数量")
|
||||
private long size;
|
||||
@ApiModelProperty("总页数")
|
||||
@Schema(description = "总页数")
|
||||
private long pages;
|
||||
@ApiModelProperty("总条数")
|
||||
@Schema(description = "总条数")
|
||||
private long total;
|
||||
@ApiModelProperty("结果集")
|
||||
@Schema(description = "结果集")
|
||||
private List<T> content;
|
||||
|
||||
|
||||
|
||||
public PageBaseResponse(List<T> list, long page, long size, long total, long pages) {
|
||||
this.page = page;
|
||||
this.size = size;
|
||||
@@ -39,7 +37,7 @@ public class PageBaseResponse<T>{
|
||||
this.content = list;
|
||||
}
|
||||
|
||||
public static <T> PageBaseResponse<T> success(IPage<T> page){
|
||||
return new PageBaseResponse<>(page.getRecords() , page.getCurrent(), page.getSize(), page.getTotal(), page.getPages());
|
||||
public static <T> PageBaseResponse<T> success(IPage<T> page) {
|
||||
return new PageBaseResponse<>(page.getRecords(), page.getCurrent(), page.getSize(), page.getTotal(), page.getPages());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,8 +1,7 @@
|
||||
package com.ai.da.common.response;
|
||||
|
||||
import com.baomidou.mybatisplus.core.metadata.IPage;
|
||||
import io.swagger.annotations.ApiModel;
|
||||
import io.swagger.annotations.ApiModelProperty;
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
@@ -16,24 +15,23 @@ import java.util.List;
|
||||
*/
|
||||
@Data
|
||||
@NoArgsConstructor
|
||||
@ApiModel("分页响应结果")
|
||||
@Schema(description = "分页响应结果")
|
||||
public class PageResponse<T> extends Response<List<T>> {
|
||||
@ApiModelProperty("页码")
|
||||
@Schema(description = "页码")
|
||||
private long page;
|
||||
@ApiModelProperty("每页数量")
|
||||
@Schema(description = "每页数量")
|
||||
private long size;
|
||||
@ApiModelProperty("总页数")
|
||||
@Schema(description = "总页数")
|
||||
private long pages;
|
||||
@ApiModelProperty("总条数")
|
||||
@Schema(description = "总条数")
|
||||
private long total;
|
||||
|
||||
@ApiModelProperty("结果集")
|
||||
@Schema(description = "结果集")
|
||||
private List<T> content;
|
||||
|
||||
|
||||
|
||||
public PageResponse(Response<List<T>> response, long page, long size, long total, long pages) {
|
||||
if(response != null) {
|
||||
if (response != null) {
|
||||
this.setData(response.getData());
|
||||
this.setErrCode(response.getErrCode());
|
||||
this.setErrMsg(response.getErrMsg());
|
||||
@@ -45,8 +43,8 @@ public class PageResponse<T> extends Response<List<T>> {
|
||||
this.content = response.getData();
|
||||
}
|
||||
|
||||
public static <T> PageResponse<T> success(IPage<T> page){
|
||||
public static <T> PageResponse<T> success(IPage<T> page) {
|
||||
Response<List<T>> response = success(page.getRecords());
|
||||
return new PageResponse<>(response , page.getCurrent(), page.getSize(), page.getTotal(), page.getPages());
|
||||
return new PageResponse<>(response, page.getCurrent(), page.getSize(), page.getTotal(), page.getPages());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
package com.ai.da.common.response;
|
||||
|
||||
import io.swagger.annotations.ApiModel;
|
||||
import io.swagger.annotations.ApiModelProperty;
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
@@ -17,38 +16,37 @@ import java.io.Serializable;
|
||||
@Data
|
||||
@AllArgsConstructor
|
||||
@NoArgsConstructor
|
||||
@ApiModel("响应结果")
|
||||
@Schema(description = "响应结果")
|
||||
public class Response<T> implements Serializable {
|
||||
|
||||
@ApiModelProperty("响应状态码 0:成功 -1:失败")
|
||||
@Schema(description = "响应状态码 0:成功 -1:失败")
|
||||
private int errCode;
|
||||
@ApiModelProperty("提示消息")
|
||||
@Schema(description = "提示消息")
|
||||
private String errMsg;
|
||||
@ApiModelProperty("数据结果")
|
||||
@Schema(description = "数据结果")
|
||||
private T data;
|
||||
|
||||
public static <T> Response<T> success(){
|
||||
public static <T> Response<T> success() {
|
||||
return success(ResultEnum.SUCCESS.getCode(), ResultEnum.SUCCESS.getMsg(), null);
|
||||
}
|
||||
|
||||
public static <T> Response<T> success(String msg){
|
||||
return success(ResultEnum.SUCCESS.getCode(), msg, null);
|
||||
}
|
||||
// public static <T> Response<T> success(String msg) {
|
||||
// return success(ResultEnum.SUCCESS.getCode(), msg, null);
|
||||
// }
|
||||
|
||||
public static <T> Response<T> success(T data){
|
||||
public static <T> Response<T> success(T data) {
|
||||
return success(ResultEnum.SUCCESS.getCode(), ResultEnum.SUCCESS.getMsg(), data);
|
||||
}
|
||||
|
||||
public static <T> Response<T> success(int code, T data){
|
||||
public static <T> Response<T> success(int code, T data) {
|
||||
return success(code, ResultEnum.SUCCESS.getMsg(), data);
|
||||
}
|
||||
|
||||
public static <T> Response<T> success(int code, String msg, T data){
|
||||
public static <T> Response<T> success(int code, String msg, T data) {
|
||||
return getResponse(code, msg, data);
|
||||
}
|
||||
|
||||
|
||||
|
||||
public static <T> Response<T> fail(String msg) {
|
||||
return fail(ResultEnum.FAIL.getCode(), msg);
|
||||
}
|
||||
@@ -85,7 +83,7 @@ public class Response<T> implements Serializable {
|
||||
return getResponse(code, msg, data);
|
||||
}
|
||||
|
||||
private static <T> Response<T> getResponse(int code, String msg, T data){
|
||||
private static <T> Response<T> getResponse(int code, String msg, T data) {
|
||||
return new Response<>(code, msg, data);
|
||||
}
|
||||
|
||||
|
||||
@@ -13,17 +13,20 @@ public enum ResultEnum {
|
||||
ERROR(false, -1, "system error!"),
|
||||
PARAMETER_ERROR(false, -2, "parameter error!"),
|
||||
|
||||
NO_LOGIN(false,-100,"User not logged in"),
|
||||
NO_PERMISSION(false,-200,"No access"),
|
||||
ACCOUNT_LOCK(false,-300,"Account frozen");
|
||||
NO_LOGIN(false, -100, "User not logged in"),
|
||||
NO_PERMISSION(false, -200, "No access"),
|
||||
ACCOUNT_LOCK(false, -300, "Account frozen"),
|
||||
|
||||
PROMPT(false, 1, "Prompt"),
|
||||
WARNING(false, 2, "Warning"),
|
||||
|
||||
;
|
||||
private int code;
|
||||
private String msg;
|
||||
private boolean isOK;
|
||||
|
||||
|
||||
|
||||
ResultEnum(boolean isOK, int code, String msg){
|
||||
ResultEnum(boolean isOK, int code, String msg) {
|
||||
this.isOK = isOK;
|
||||
this.code = code;
|
||||
this.msg = msg;
|
||||
|
||||
@@ -0,0 +1,15 @@
|
||||
package com.ai.da.common.response;
|
||||
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
|
||||
@Data
|
||||
@NoArgsConstructor
|
||||
@Schema(description = "交易记录分页响应结果")
|
||||
public class TransactionPageResponse<T> extends PageBaseResponse<T> {
|
||||
|
||||
private BigDecimal totalAmount;
|
||||
}
|
||||
@@ -7,8 +7,8 @@ import org.springframework.security.access.AccessDeniedException;
|
||||
import org.springframework.security.web.access.AccessDeniedHandler;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
import jakarta.servlet.http.HttpServletRequest;
|
||||
import jakarta.servlet.http.HttpServletResponse;
|
||||
import java.io.IOException;
|
||||
|
||||
/**
|
||||
|
||||
@@ -7,9 +7,9 @@ import org.springframework.security.core.AuthenticationException;
|
||||
import org.springframework.security.web.AuthenticationEntryPoint;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import javax.servlet.ServletException;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
import jakarta.servlet.ServletException;
|
||||
import jakarta.servlet.http.HttpServletRequest;
|
||||
import jakarta.servlet.http.HttpServletResponse;
|
||||
import java.io.IOException;
|
||||
|
||||
/**
|
||||
|
||||
@@ -5,7 +5,7 @@ import org.springframework.security.core.Authentication;
|
||||
import org.springframework.security.core.AuthenticationException;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
import jakarta.annotation.Resource;
|
||||
|
||||
/**
|
||||
* @author: dangweijian
|
||||
|
||||
@@ -10,9 +10,9 @@ import org.springframework.security.core.userdetails.UsernameNotFoundException;
|
||||
import org.springframework.security.web.authentication.AuthenticationFailureHandler;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import javax.servlet.ServletException;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
import jakarta.servlet.ServletException;
|
||||
import jakarta.servlet.http.HttpServletRequest;
|
||||
import jakarta.servlet.http.HttpServletResponse;
|
||||
import java.io.IOException;
|
||||
|
||||
/**
|
||||
@@ -43,6 +43,6 @@ public class UserLoginFailureHandler implements AuthenticationFailureHandler {
|
||||
log.error("登录失败:", e);
|
||||
response = Response.fail("登录失败!");
|
||||
}
|
||||
JSONResponseUtils.build(httpServletResponse,response);
|
||||
JSONResponseUtils.build(httpServletResponse, response);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -8,10 +8,10 @@ import org.springframework.security.core.Authentication;
|
||||
import org.springframework.security.web.authentication.AuthenticationSuccessHandler;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
import javax.servlet.ServletException;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
import jakarta.annotation.Resource;
|
||||
import jakarta.servlet.ServletException;
|
||||
import jakarta.servlet.http.HttpServletRequest;
|
||||
import jakarta.servlet.http.HttpServletResponse;
|
||||
import java.io.IOException;
|
||||
|
||||
/**
|
||||
|
||||
@@ -1,84 +1,107 @@
|
||||
package com.ai.da.common.security.config;
|
||||
|
||||
import com.ai.da.common.security.*;
|
||||
import com.ai.da.common.security.filter.AuthenticationFilter;
|
||||
import com.ai.da.common.security.filter.UserAuthenticationProcessingFilter;
|
||||
import org.springframework.boot.context.properties.EnableConfigurationProperties;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.security.authentication.AuthenticationManager;
|
||||
import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;
|
||||
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
|
||||
import org.springframework.security.config.annotation.web.builders.WebSecurity;
|
||||
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
|
||||
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
|
||||
import org.springframework.security.config.http.SessionCreationPolicy;
|
||||
import org.springframework.security.web.access.expression.DefaultWebSecurityExpressionHandler;
|
||||
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
|
||||
import org.springframework.security.web.authentication.www.BasicAuthenticationFilter;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
|
||||
@EnableWebSecurity
|
||||
@EnableGlobalMethodSecurity(prePostEnabled = true)
|
||||
@EnableConfigurationProperties(SecurityProperties.class)
|
||||
public class SecurityConfig extends WebSecurityConfigurerAdapter {
|
||||
|
||||
@Resource
|
||||
private SecurityProperties securityProperties;
|
||||
@Resource
|
||||
private UserLoginSuccessHandler userLoginSuccessHandler;
|
||||
@Resource
|
||||
private UserLoginFailureHandler userLoginFailureHandler;
|
||||
@Resource
|
||||
private UserAuthAccessDeniedHandler userAuthAccessDeniedHandler;
|
||||
@Resource
|
||||
private UserAuthenticationEntryPointHandler userAuthenticationEntryPointHandler;
|
||||
@Resource
|
||||
private UserAuthenticationManager userAuthenticationManager;
|
||||
@Resource
|
||||
private UserAuthenticationProcessingFilter userAuthenticationProcessingFilter;
|
||||
|
||||
/**
|
||||
* 不通过注入spring管理 让Security来管理 这样自定义的Filter就不会走,.permitAll()才能起作用
|
||||
*/
|
||||
@Resource
|
||||
private AuthenticationFilter authenticationFilter;
|
||||
@Resource
|
||||
private UserPermissionEvaluator userPermissionEvaluator;
|
||||
|
||||
|
||||
@Override
|
||||
public AuthenticationManager authenticationManagerBean() throws Exception {
|
||||
return this.userAuthenticationManager;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void configure(HttpSecurity httpSecurity/*, WebSecurity web*/) throws Exception {
|
||||
// web.ignoring().antMatchers("/test/**");//禁止所有过滤器
|
||||
httpSecurity.cors().disable()//禁用 CSRF
|
||||
.authorizeRequests()//认证请求
|
||||
.antMatchers(securityProperties.getIgnorePaths()).permitAll()//忽略的请求
|
||||
.anyRequest().authenticated()//其余所有的请求都需要认证
|
||||
.and().headers().frameOptions().disable()// 防止iframe 造成跨域
|
||||
.and().exceptionHandling().authenticationEntryPoint(userAuthenticationEntryPointHandler)//未登录请求处理
|
||||
.accessDeniedHandler(userAuthAccessDeniedHandler)//无权限访问处理类 (此配置可以忽略,全局异常会先于Security框架处理异常,全局异常已特殊处理)
|
||||
.and().formLogin().loginProcessingUrl(securityProperties.getAuthApi())//指定认证接口
|
||||
.successHandler(userLoginSuccessHandler)//登录成功处理器
|
||||
.failureHandler(userLoginFailureHandler)//登录失败处理器
|
||||
.and().cors().and().csrf().disable();//允许跨域
|
||||
//自定义过滤器在登录时认证用户名、密码
|
||||
httpSecurity.addFilterAt(userAuthenticationProcessingFilter, UsernamePasswordAuthenticationFilter.class)
|
||||
.addFilterBefore(authenticationFilter, BasicAuthenticationFilter.class);
|
||||
//不创建session会话
|
||||
httpSecurity.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS);
|
||||
//取消头缓存控制
|
||||
httpSecurity.headers().cacheControl();
|
||||
}
|
||||
|
||||
@Bean
|
||||
public DefaultWebSecurityExpressionHandler userSecurityExpressionHandler() {
|
||||
DefaultWebSecurityExpressionHandler handler = new DefaultWebSecurityExpressionHandler();
|
||||
handler.setPermissionEvaluator(userPermissionEvaluator);
|
||||
return handler;
|
||||
}
|
||||
}
|
||||
package com.ai.da.common.security.config;
|
||||
|
||||
import com.ai.da.common.security.*;
|
||||
import com.ai.da.common.security.filter.AuthenticationFilter;
|
||||
import com.ai.da.common.security.filter.UserAuthenticationProcessingFilter;
|
||||
import org.springframework.boot.context.properties.EnableConfigurationProperties;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.security.authentication.AuthenticationManager;
|
||||
import org.springframework.security.config.Customizer;
|
||||
import org.springframework.security.config.annotation.method.configuration.EnableMethodSecurity;
|
||||
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
|
||||
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
|
||||
import org.springframework.security.config.annotation.web.configurers.AbstractHttpConfigurer;
|
||||
import org.springframework.security.config.annotation.web.configurers.HeadersConfigurer;
|
||||
import org.springframework.security.config.http.SessionCreationPolicy;
|
||||
import org.springframework.security.web.SecurityFilterChain;
|
||||
import org.springframework.security.web.access.expression.DefaultWebSecurityExpressionHandler;
|
||||
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
|
||||
import org.springframework.security.web.authentication.www.BasicAuthenticationFilter;
|
||||
import org.springframework.security.web.util.matcher.AntPathRequestMatcher;
|
||||
|
||||
import jakarta.annotation.Resource;
|
||||
|
||||
@Configuration
|
||||
@EnableWebSecurity
|
||||
@EnableMethodSecurity(prePostEnabled = true)
|
||||
@EnableConfigurationProperties(SecurityProperties.class)
|
||||
public class SecurityConfig {
|
||||
|
||||
@Resource
|
||||
private SecurityProperties securityProperties;
|
||||
@Resource
|
||||
private UserLoginSuccessHandler userLoginSuccessHandler;
|
||||
@Resource
|
||||
private UserLoginFailureHandler userLoginFailureHandler;
|
||||
@Resource
|
||||
private UserAuthAccessDeniedHandler userAuthAccessDeniedHandler;
|
||||
@Resource
|
||||
private UserAuthenticationEntryPointHandler userAuthenticationEntryPointHandler;
|
||||
@Resource
|
||||
private UserAuthenticationManager userAuthenticationManager;
|
||||
@Resource
|
||||
private UserAuthenticationProcessingFilter userAuthenticationProcessingFilter;
|
||||
|
||||
/**
|
||||
* 不通过注入spring管理 让Security来管理 这样自定义的Filter就不会走,.permitAll()才能起作用
|
||||
*/
|
||||
@Resource
|
||||
private AuthenticationFilter authenticationFilter;
|
||||
@Resource
|
||||
private UserPermissionEvaluator userPermissionEvaluator;
|
||||
|
||||
@Bean
|
||||
public AuthenticationManager authenticationManager() throws Exception {
|
||||
return this.userAuthenticationManager;
|
||||
}
|
||||
|
||||
@Bean
|
||||
public SecurityFilterChain securityFilterChain(HttpSecurity httpSecurity) throws Exception {
|
||||
httpSecurity
|
||||
.cors(Customizer.withDefaults())
|
||||
.authorizeHttpRequests(auth -> auth
|
||||
.requestMatchers(
|
||||
new AntPathRequestMatcher("/doc.html"),
|
||||
new AntPathRequestMatcher("/swagger-ui.html"),
|
||||
new AntPathRequestMatcher("/swagger-ui/**"),
|
||||
new AntPathRequestMatcher("/swagger-resources/**"),
|
||||
new AntPathRequestMatcher("/v2/api-docs"),
|
||||
new AntPathRequestMatcher("/v3/api-docs/**"),
|
||||
new AntPathRequestMatcher("/webjars/**")
|
||||
).permitAll()
|
||||
.requestMatchers(securityProperties.getIgnorePaths()).permitAll()
|
||||
.anyRequest().authenticated()
|
||||
)
|
||||
.headers(headers -> headers
|
||||
.frameOptions(HeadersConfigurer.FrameOptionsConfig::disable)
|
||||
.cacheControl(cache -> cache.disable())
|
||||
)
|
||||
.exceptionHandling(exception -> exception
|
||||
.authenticationEntryPoint(userAuthenticationEntryPointHandler)
|
||||
.accessDeniedHandler(userAuthAccessDeniedHandler)
|
||||
)
|
||||
.formLogin(form -> form
|
||||
.loginProcessingUrl(securityProperties.getAuthApi())
|
||||
.successHandler(userLoginSuccessHandler)
|
||||
.failureHandler(userLoginFailureHandler)
|
||||
)
|
||||
.csrf(AbstractHttpConfigurer::disable)
|
||||
.sessionManagement(session -> session
|
||||
.sessionCreationPolicy(SessionCreationPolicy.STATELESS)
|
||||
);
|
||||
|
||||
//自定义过滤器在登录时认证用户名、密码
|
||||
httpSecurity.addFilterAt(userAuthenticationProcessingFilter, UsernamePasswordAuthenticationFilter.class)
|
||||
.addFilterBefore(authenticationFilter, BasicAuthenticationFilter.class);
|
||||
|
||||
return httpSecurity.build();
|
||||
}
|
||||
|
||||
@Bean
|
||||
public DefaultWebSecurityExpressionHandler userSecurityExpressionHandler() {
|
||||
DefaultWebSecurityExpressionHandler handler = new DefaultWebSecurityExpressionHandler();
|
||||
handler.setPermissionEvaluator(userPermissionEvaluator);
|
||||
return handler;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,122 +1,165 @@
|
||||
package com.ai.da.common.security.filter;
|
||||
|
||||
import cn.hutool.core.util.StrUtil;
|
||||
import com.ai.da.common.context.UserContext;
|
||||
import com.ai.da.common.security.config.SecurityProperties;
|
||||
import com.ai.da.common.security.jwt.JWTTokenHelper;
|
||||
import com.ai.da.common.utils.LocalCacheUtils;
|
||||
import com.ai.da.common.utils.MultiReadHttpServletRequest;
|
||||
import com.ai.da.common.utils.MultiReadHttpServletResponse;
|
||||
import com.ai.da.model.vo.AuthPrincipalVo;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.beans.factory.annotation.Required;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.lang.NonNull;
|
||||
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
|
||||
import org.springframework.security.core.context.SecurityContextHolder;
|
||||
import org.springframework.util.StopWatch;
|
||||
import org.springframework.util.StringUtils;
|
||||
import org.springframework.web.bind.annotation.RequestBody;
|
||||
import org.springframework.web.filter.OncePerRequestFilter;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
import javax.security.sasl.AuthenticationException;
|
||||
import javax.servlet.FilterChain;
|
||||
import javax.servlet.ServletException;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
import java.io.IOException;
|
||||
import java.sql.Statement;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* @author: dangweijian
|
||||
* @description: 认证拦截器
|
||||
* @create: 2020-07-10 16:50
|
||||
**/
|
||||
@Slf4j
|
||||
@Configuration
|
||||
public class AuthenticationFilter extends OncePerRequestFilter {
|
||||
|
||||
@Resource
|
||||
private JWTTokenHelper jwtTokenHelper;
|
||||
@Resource
|
||||
private SecurityProperties properties;
|
||||
|
||||
private static final List<String> FILTER_URL =
|
||||
Arrays.asList("/favicon.ico","/doc.html","api/account/login","api/account/preLogin","api/account/sendEmail",
|
||||
"/webjars/","/swagger-resources","/v2/api-docs","api/account/resetPwd",
|
||||
"/api/python/saveGeneratePicture", "/api/python/getLibraryByUserId",
|
||||
"/api/third/party/addUser","/api/third/party/editUser","/api/element/initDefaultSysFile");
|
||||
|
||||
@Override
|
||||
protected void doFilterInternal(HttpServletRequest httpServletRequest, @NonNull HttpServletResponse httpServletResponse, @NonNull FilterChain filterChain) throws ServletException, IOException {
|
||||
String requestURI = httpServletRequest.getRequestURI();
|
||||
|
||||
if(calculateUrl(requestURI)){
|
||||
StopWatch stopWatch = new StopWatch();
|
||||
HttpServletRequest wrappedRequest = httpServletRequest;
|
||||
HttpServletResponse wrappedResponse = httpServletResponse;
|
||||
try{
|
||||
stopWatch.start();
|
||||
if ((httpServletRequest.getContentType() == null && httpServletRequest.getContentLength() > 0) || (httpServletRequest.getContentType() != null && !httpServletRequest.getContentType().contains("application/json"))) {
|
||||
extracted(wrappedRequest);
|
||||
filterChain.doFilter(wrappedRequest, wrappedResponse);
|
||||
}else {
|
||||
wrappedRequest = new MultiReadHttpServletRequest(httpServletRequest);
|
||||
wrappedResponse = new MultiReadHttpServletResponse(httpServletResponse);
|
||||
extracted(wrappedRequest);
|
||||
filterChain.doFilter(wrappedRequest, wrappedResponse);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
SecurityContextHolder.clearContext();
|
||||
throw e;
|
||||
} finally {
|
||||
stopWatch.stop();
|
||||
}
|
||||
}else {
|
||||
filterChain.doFilter(httpServletRequest, httpServletResponse);
|
||||
}
|
||||
}
|
||||
private Boolean calculateUrl(String requestURI ){
|
||||
String filterUrl = FILTER_URL.stream().filter(url ->requestURI.contains(url)).findFirst().orElse(null);
|
||||
return null == filterUrl ? Boolean.TRUE :Boolean.FALSE;
|
||||
}
|
||||
private void extracted(HttpServletRequest request) throws AuthenticationException {
|
||||
String jwtToken = request.getHeader(properties.getJwtTokenHeader());
|
||||
log.debug("后台检查令牌:{}", jwtToken);
|
||||
|
||||
if (StrUtil.isBlank(jwtToken)) {
|
||||
throw new RuntimeException("请传入token!");
|
||||
}
|
||||
// 检查token
|
||||
boolean validate = jwtTokenHelper.validateToken(jwtToken);
|
||||
if(validate){
|
||||
AuthPrincipalVo principal = jwtTokenHelper.parserToUser(jwtToken);
|
||||
if (principal == null) {
|
||||
throw new RuntimeException("TOKEN已过期,请重新登录!");
|
||||
}
|
||||
//先清空当前线程变量,防止上一个线程遗留
|
||||
UserContext.delete();
|
||||
//存取用户信息到缓存
|
||||
UserContext.setUserHolder(principal);
|
||||
//校验token
|
||||
String cacheToken = LocalCacheUtils.getTokenCache(String.valueOf(principal.getId()));
|
||||
if(jwtToken.equals("Bearer-eyJhbGciOiJIUzUxMiJ9.eyJqdGkiOiIyIiwic3ViIjoie1wiaWRcIjoyLFwidXNlcm5hbWVcIjpcImxpcnNcIn0iLCJpYXQiOjE2NjU3NDEwODcsImlzcyI6IkRXSiIsImF1dGhvcml0aWVzIjoiW10iLCJleHAiOjE2NzQzODEwODd9.ShM9R_NNFD7oo1OvxrEgg7PFeWinOuAKkuInUCMQupp66s64Hhv8tN0Wwr83nIN4rHPqtn95wmd4msWcvaFYJA")){
|
||||
//写死 暂时放行
|
||||
return;
|
||||
}
|
||||
if(StringUtils.isEmpty(cacheToken)){
|
||||
throw new RuntimeException("TOKEN已过期,请重新登录!");
|
||||
}
|
||||
if(!cacheToken.equals(jwtToken) ){
|
||||
throw new RuntimeException("TOKEN已过期,请重新登录!");
|
||||
}
|
||||
// UsernamePasswordAuthenticationToken authentication = new UsernamePasswordAuthenticationToken(null, null);
|
||||
// SecurityContextHolder.getContext().setAuthentication(authentication);
|
||||
}
|
||||
}
|
||||
}
|
||||
package com.ai.da.common.security.filter;
|
||||
|
||||
import cn.hutool.core.util.StrUtil;
|
||||
import com.ai.da.common.config.exception.TokenMissingOrExpiredException;
|
||||
import com.ai.da.common.context.UserContext;
|
||||
import com.ai.da.common.security.config.SecurityProperties;
|
||||
import com.ai.da.common.security.jwt.JWTTokenHelper;
|
||||
import com.ai.da.common.utils.LocalCacheUtils;
|
||||
import com.ai.da.common.utils.RedisUtil;
|
||||
import com.ai.da.common.utils.MultiReadHttpServletRequest;
|
||||
import com.ai.da.common.utils.MultiReadHttpServletResponse;
|
||||
import com.ai.da.common.utils.RequestInfoUtil;
|
||||
import com.ai.da.model.vo.AuthPrincipalVo;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.lang.NonNull;
|
||||
import org.springframework.security.core.context.SecurityContextHolder;
|
||||
import org.springframework.util.StopWatch;
|
||||
import org.springframework.util.StringUtils;
|
||||
import org.springframework.web.filter.OncePerRequestFilter;
|
||||
|
||||
import jakarta.annotation.Resource;
|
||||
import jakarta.servlet.FilterChain;
|
||||
import jakarta.servlet.ServletException;
|
||||
import jakarta.servlet.http.HttpServletRequest;
|
||||
import jakarta.servlet.http.HttpServletResponse;
|
||||
import java.io.IOException;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* @author: dangweijian
|
||||
* @description: 认证拦截器
|
||||
* @create: 2020-07-10 16:50
|
||||
**/
|
||||
@Slf4j
|
||||
@Configuration
|
||||
public class AuthenticationFilter extends OncePerRequestFilter {
|
||||
|
||||
@Resource
|
||||
private JWTTokenHelper jwtTokenHelper;
|
||||
@Resource
|
||||
private SecurityProperties properties;
|
||||
@Resource
|
||||
private RedisUtil redisUtil;
|
||||
|
||||
private static final List<String> FILTER_URL =
|
||||
Arrays.asList("/favicon.ico", "/doc.html", "/swagger-ui.html",
|
||||
"/swagger-resources", "/swagger-resources/", "/swagger-resources/configuration/ui", "/swagger-resources/configuration/security",
|
||||
"/webjars/", "/v2/api-docs", "/v3/api-docs", "/v3/api-docs/swagger-config",
|
||||
"/api/account/login", "/api/account/preLogin", "api/account/sendEmail","api/account/noLoginRequired",
|
||||
"/api/account/resetPwd",
|
||||
"/api/python/saveGeneratePicture", "/api/python/getLibraryByUserId",
|
||||
"/api/third/party/addUser","/api/third/party/addTrialUser", "/api/third/party/editUser", "/api/element/initDefaultSysFile",
|
||||
"/api/third/party/addNoLoginRequiredNew","/api/third/party/deleteNoLoginRequiredNew","/api/third/party/updateNoLoginRequiredNew",
|
||||
"/api/third/party/existNoLoginRequired","/api/third/party/getRedirectUrl",
|
||||
"/api/python/flush","/api/account/healthy","/api/ali-pay/trade/notify","/api/paypal/ipn/back","/api/alipay-hk/trade/notify",
|
||||
"/api/portfolio/page", "/api/portfolio/detail", "/api/portfolio/commentPage", "/api/portfolio/viewsIncrease",
|
||||
"/api/account/designWorksRegister","/api/account/questionnaire","/api/stripe/trade/notify",
|
||||
"/notification","/api/account/activateNewEmail","/api/third/party/auth/google_callback","/api/third/party/parseGoogleCredential","/api/third/party/receiveDesignResults","/api/third/party/parseWeChatCode","/api/third/party/receiveDesignParams"
|
||||
, "/api/account/schoolLogin", "/api/account/enterpriseLogin", "/api/account/organizationNameSearch",
|
||||
"/api/llm/stream",
|
||||
//GlobalAwardController
|
||||
"/api/global-award/uploads/pdf/init", "/api/global-award/uploads/pdf/chunk", "/api/global-award/uploads/pdf/complete", "/api/global-award/uploads/pdf/status",
|
||||
"/api/global-award/uploads/video/init", "/api/global-award/uploads/video/chunk", "/api/global-award/uploads/video/complete", "/api/global-award/uploads/video/status",
|
||||
"/api/global-award/contestants/save", "/api/global-award/contestants/by-email", "/api/global-award/checkEmail", "/api/global-award/checkCode","/api/global-award/contestants/export",
|
||||
"/api/global-award/contestants/export/files", "/api/global-award/contestants/count"
|
||||
);
|
||||
|
||||
@Override
|
||||
protected void doFilterInternal(HttpServletRequest httpServletRequest, @NonNull HttpServletResponse httpServletResponse, @NonNull FilterChain filterChain) throws ServletException, IOException {
|
||||
String requestURI = httpServletRequest.getRequestURI();
|
||||
|
||||
if (calculateUrl(requestURI)/* || hasAuthorizationToken(httpServletRequest)*/) {
|
||||
StopWatch stopWatch = new StopWatch();
|
||||
HttpServletRequest wrappedRequest = httpServletRequest;
|
||||
HttpServletResponse wrappedResponse = httpServletResponse;
|
||||
try {
|
||||
stopWatch.start();
|
||||
if ((httpServletRequest.getContentType() == null && httpServletRequest.getContentLength() > 0) || (httpServletRequest.getContentType() != null && !httpServletRequest.getContentType().contains("application/json"))) {
|
||||
extracted(wrappedRequest);
|
||||
filterChain.doFilter(wrappedRequest, wrappedResponse);
|
||||
} else {
|
||||
wrappedRequest = new MultiReadHttpServletRequest(httpServletRequest);
|
||||
wrappedResponse = new MultiReadHttpServletResponse(httpServletResponse);
|
||||
extracted(wrappedRequest);
|
||||
// excel导出使用原始response,不对响应做包装
|
||||
if (requestURI.equals("/api/account/exportAccountsToExcel")) {
|
||||
filterChain.doFilter(httpServletRequest, httpServletResponse); // 不包装
|
||||
} else {
|
||||
filterChain.doFilter(wrappedRequest, wrappedResponse);
|
||||
}
|
||||
}
|
||||
} catch (Exception e) {
|
||||
SecurityContextHolder.clearContext();
|
||||
throw e;
|
||||
} finally {
|
||||
stopWatch.stop();
|
||||
}
|
||||
} else {
|
||||
//先清空当前线程变量,防止上一个线程遗留
|
||||
UserContext.delete();
|
||||
filterChain.doFilter(httpServletRequest, httpServletResponse);
|
||||
}
|
||||
}
|
||||
|
||||
private Boolean calculateUrl(String requestURI) {
|
||||
String filterUrl = FILTER_URL.stream().filter(url -> requestURI.contains(url)).findFirst().orElse(null);
|
||||
return null == filterUrl ? Boolean.TRUE : Boolean.FALSE;
|
||||
}
|
||||
|
||||
private boolean hasAuthorizationToken(HttpServletRequest request) {
|
||||
String authorizationHeader = request.getHeader("Authorization");
|
||||
return authorizationHeader != null && authorizationHeader.startsWith("Bearer");
|
||||
}
|
||||
|
||||
private void extracted(HttpServletRequest request) {
|
||||
String jwtToken = request.getHeader(properties.getJwtTokenHeader());
|
||||
// log.debug("后台检查令牌:{}", jwtToken);
|
||||
|
||||
if (StrUtil.isBlank(jwtToken)) {
|
||||
String ipAddress = RequestInfoUtil.getIpAddress(request);
|
||||
log.info("本次请求的ip为 : " + ipAddress);
|
||||
// throw new RuntimeException("请传入token!");
|
||||
throw new TokenMissingOrExpiredException("请传入token!");
|
||||
}
|
||||
if(jwtToken.equals("Bearer-eyJhbGciOiJIUzUxMiJ9.eyJqdGkiOiIyIiwic3ViIjoie1wiaWRcIjoyLFwidXNlcm5hbWVcIjpcImxpcnNcIn0iLCJpYXQiOjE2NjU3NDEwODcsImlzcyI6IkRXSiIsImF1dGhvcml0aWVzIjoiW10iLCJleHAiOjE2NzQzODEwODd9.ShM9R_NNFD7oo1OvxrEgg7PFeWinOuAKkuInUCMQupp66s64Hhv8tN0Wwr83nIN4rHPqtn95wmd4msWcvaFYJA")){
|
||||
//写死 暂时放行
|
||||
return;
|
||||
}
|
||||
// 检查token
|
||||
boolean validate = jwtTokenHelper.validateToken(jwtToken);
|
||||
if (validate) {
|
||||
AuthPrincipalVo principal = jwtTokenHelper.parserToUser(jwtToken);
|
||||
if (principal == null) {
|
||||
// throw new RuntimeException("TOKEN已过期,请重新登录!");
|
||||
throw new TokenMissingOrExpiredException("TOKEN已过期,请重新登录!(token without userInfo)");
|
||||
}
|
||||
//先清空当前线程变量,防止上一个线程遗留
|
||||
UserContext.delete();
|
||||
//存取用户信息到缓存
|
||||
UserContext.setUserHolder(principal);
|
||||
// 校验 token:先查本地缓存,再查 Redis,保证服务重启后仍然有效
|
||||
String userIdStr = String.valueOf(principal.getId());
|
||||
String cacheToken = LocalCacheUtils.getTokenCache(userIdStr);
|
||||
|
||||
if (StringUtils.isEmpty(cacheToken)) {
|
||||
// 本地缓存为空时,尝试从 Redis 读取
|
||||
cacheToken = redisUtil.getLoginToken(principal.getId());
|
||||
if (StringUtils.isEmpty(cacheToken)) {
|
||||
// throw new RuntimeException("TOKEN已过期,请重新登录!");
|
||||
throw new TokenMissingOrExpiredException("TOKEN已过期,请重新登录!(cache & redis empty)");
|
||||
}
|
||||
// 将 Redis 中的 token 回填到本地缓存,减少后续 Redis 访问
|
||||
LocalCacheUtils.setTokenCache(userIdStr, cacheToken);
|
||||
}
|
||||
if(!cacheToken.equals(jwtToken) ){
|
||||
// throw new RuntimeException("TOKEN已过期,请重新登录!");
|
||||
throw new TokenMissingOrExpiredException("TOKEN已过期,请重新登录!(token not match local cache)");
|
||||
}
|
||||
// UsernamePasswordAuthenticationToken authentication = new UsernamePasswordAuthenticationToken(null, null);
|
||||
// SecurityContextHolder.getContext().setAuthentication(authentication);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,69 +1,69 @@
|
||||
package com.ai.da.common.security.filter;
|
||||
|
||||
import cn.hutool.core.util.StrUtil;
|
||||
import com.ai.da.common.security.UserLoginSuccessHandler;
|
||||
import com.ai.da.common.security.config.SecurityProperties;
|
||||
import com.ai.da.common.utils.RedisCacheUtils;
|
||||
import com.alibaba.fastjson.JSONObject;
|
||||
import com.ai.da.common.security.UserAuthenticationManager;
|
||||
import com.ai.da.common.security.UserLoginFailureHandler;
|
||||
import com.ai.da.common.utils.MultiReadHttpServletRequest;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.http.HttpMethod;
|
||||
import org.springframework.security.authentication.AuthenticationServiceException;
|
||||
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
|
||||
import org.springframework.security.core.Authentication;
|
||||
import org.springframework.security.core.AuthenticationException;
|
||||
import org.springframework.security.web.authentication.AbstractAuthenticationProcessingFilter;
|
||||
import org.springframework.security.web.util.matcher.AntPathRequestMatcher;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
|
||||
/**
|
||||
* @author: dangweijian
|
||||
* @description: 用户认证过滤器
|
||||
* @create: 2020-07-10 15:58
|
||||
**/
|
||||
@Slf4j
|
||||
@Component
|
||||
public class UserAuthenticationProcessingFilter extends AbstractAuthenticationProcessingFilter {
|
||||
|
||||
/**
|
||||
* @param securityProperties 配置(从配置中读取登录url)
|
||||
* @param authenticationManager 认证管理器
|
||||
* @param adminAuthenticationSuccessHandler 认证成功处理器
|
||||
* @param adminAuthenticationFailureHandler 认证失败处理器
|
||||
*/
|
||||
public UserAuthenticationProcessingFilter(SecurityProperties securityProperties, UserAuthenticationManager authenticationManager, UserLoginSuccessHandler adminAuthenticationSuccessHandler, UserLoginFailureHandler adminAuthenticationFailureHandler) {
|
||||
super(new AntPathRequestMatcher(securityProperties.getAuthApi(), HttpMethod.POST.name()));
|
||||
this.setAuthenticationManager(authenticationManager);
|
||||
this.setAuthenticationSuccessHandler(adminAuthenticationSuccessHandler);
|
||||
this.setAuthenticationFailureHandler(adminAuthenticationFailureHandler);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Authentication attemptAuthentication(HttpServletRequest request, HttpServletResponse response) throws AuthenticationException {
|
||||
if (request.getContentType() == null || !request.getContentType().contains("application/json")) {
|
||||
throw new AuthenticationServiceException("请求头类型不支持: " + request.getContentType());
|
||||
}
|
||||
UsernamePasswordAuthenticationToken authRequest;
|
||||
try {
|
||||
MultiReadHttpServletRequest wrappedRequest = new MultiReadHttpServletRequest(request);
|
||||
// 将前端传递的数据转换成jsonBean数据格式
|
||||
JSONObject jsonObject = JSONObject.parseObject(wrappedRequest.getBodyJsonStrByJson(wrappedRequest));
|
||||
String code = jsonObject.getString("code");
|
||||
String uuid = jsonObject.getString("uuid");
|
||||
if (StrUtil.isEmpty(code) || StrUtil.isEmpty(uuid) || !code.equals(RedisCacheUtils.get("code-key-" + uuid, String.class))) {
|
||||
throw new AuthenticationServiceException("验证码错误");
|
||||
}
|
||||
RedisCacheUtils.delete("code-key-" + uuid);
|
||||
authRequest = new UsernamePasswordAuthenticationToken(jsonObject.get("username"), jsonObject.get("password"), null);
|
||||
authRequest.setDetails(authenticationDetailsSource.buildDetails(wrappedRequest));
|
||||
} catch (Exception e) {
|
||||
throw new AuthenticationServiceException(e.getMessage());
|
||||
}
|
||||
return this.getAuthenticationManager().authenticate(authRequest);
|
||||
}
|
||||
}
|
||||
package com.ai.da.common.security.filter;
|
||||
|
||||
import cn.hutool.core.util.StrUtil;
|
||||
import com.ai.da.common.security.UserLoginSuccessHandler;
|
||||
import com.ai.da.common.security.config.SecurityProperties;
|
||||
import com.ai.da.common.utils.RedisCacheUtils;
|
||||
import com.alibaba.fastjson.JSONObject;
|
||||
import com.ai.da.common.security.UserAuthenticationManager;
|
||||
import com.ai.da.common.security.UserLoginFailureHandler;
|
||||
import com.ai.da.common.utils.MultiReadHttpServletRequest;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.http.HttpMethod;
|
||||
import org.springframework.security.authentication.AuthenticationServiceException;
|
||||
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
|
||||
import org.springframework.security.core.Authentication;
|
||||
import org.springframework.security.core.AuthenticationException;
|
||||
import org.springframework.security.web.authentication.AbstractAuthenticationProcessingFilter;
|
||||
import org.springframework.security.web.util.matcher.AntPathRequestMatcher;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import jakarta.servlet.http.HttpServletRequest;
|
||||
import jakarta.servlet.http.HttpServletResponse;
|
||||
|
||||
/**
|
||||
* @author: dangweijian
|
||||
* @description: 用户认证过滤器
|
||||
* @create: 2020-07-10 15:58
|
||||
**/
|
||||
@Slf4j
|
||||
@Component
|
||||
public class UserAuthenticationProcessingFilter extends AbstractAuthenticationProcessingFilter {
|
||||
|
||||
/**
|
||||
* @param securityProperties 配置(从配置中读取登录url)
|
||||
* @param authenticationManager 认证管理器
|
||||
* @param adminAuthenticationSuccessHandler 认证成功处理器
|
||||
* @param adminAuthenticationFailureHandler 认证失败处理器
|
||||
*/
|
||||
public UserAuthenticationProcessingFilter(SecurityProperties securityProperties, UserAuthenticationManager authenticationManager, UserLoginSuccessHandler adminAuthenticationSuccessHandler, UserLoginFailureHandler adminAuthenticationFailureHandler) {
|
||||
super(new AntPathRequestMatcher(securityProperties.getAuthApi(), HttpMethod.POST.name()));
|
||||
this.setAuthenticationManager(authenticationManager);
|
||||
this.setAuthenticationSuccessHandler(adminAuthenticationSuccessHandler);
|
||||
this.setAuthenticationFailureHandler(adminAuthenticationFailureHandler);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Authentication attemptAuthentication(HttpServletRequest request, HttpServletResponse response) throws AuthenticationException {
|
||||
if (request.getContentType() == null || !request.getContentType().contains("application/json")) {
|
||||
throw new AuthenticationServiceException("请求头类型不支持: " + request.getContentType());
|
||||
}
|
||||
UsernamePasswordAuthenticationToken authRequest;
|
||||
try {
|
||||
MultiReadHttpServletRequest wrappedRequest = new MultiReadHttpServletRequest(request);
|
||||
// 将前端传递的数据转换成jsonBean数据格式
|
||||
JSONObject jsonObject = JSONObject.parseObject(wrappedRequest.getBodyJsonStrByJson(wrappedRequest));
|
||||
String code = jsonObject.getString("code");
|
||||
String uuid = jsonObject.getString("uuid");
|
||||
if (StrUtil.isEmpty(code) || StrUtil.isEmpty(uuid) || !code.equals(RedisCacheUtils.get("code-key-" + uuid, String.class))) {
|
||||
throw new AuthenticationServiceException("验证码错误");
|
||||
}
|
||||
RedisCacheUtils.delete("code-key-" + uuid);
|
||||
authRequest = new UsernamePasswordAuthenticationToken(jsonObject.get("username"), jsonObject.get("password"), null);
|
||||
authRequest.setDetails(authenticationDetailsSource.buildDetails(wrappedRequest));
|
||||
} catch (Exception e) {
|
||||
throw new AuthenticationServiceException(e.getMessage());
|
||||
}
|
||||
return this.getAuthenticationManager().authenticate(authRequest);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,68 +1,108 @@
|
||||
package com.ai.da.common.security.jwt;
|
||||
|
||||
import cn.hutool.core.map.MapUtil;
|
||||
import cn.hutool.core.util.StrUtil;
|
||||
import com.ai.da.common.security.config.SecurityProperties;
|
||||
import com.ai.da.model.vo.AuthPrincipalVo;
|
||||
import com.alibaba.fastjson.JSON;
|
||||
import com.alibaba.fastjson.JSONObject;
|
||||
import io.jsonwebtoken.Claims;
|
||||
import io.jsonwebtoken.Jwts;
|
||||
import io.jsonwebtoken.SignatureAlgorithm;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Date;
|
||||
|
||||
/**
|
||||
* @author: dangweijian
|
||||
* @description: JWT工具
|
||||
* @create: 2020-07-09 09:27
|
||||
**/
|
||||
@Slf4j
|
||||
@Component
|
||||
public class JWTTokenHelper {
|
||||
|
||||
@Resource
|
||||
private SecurityProperties securityProperties;
|
||||
|
||||
private static final String ISSUER = "DWJ";
|
||||
private static final String AUTHORITIES = "authorities";
|
||||
|
||||
public String createToken(AuthPrincipalVo principal){
|
||||
String token = Jwts.builder()
|
||||
.setId(String.valueOf(principal.getId()))
|
||||
.setSubject(JSONObject.toJSONString(principal))
|
||||
.setIssuedAt(new Date())
|
||||
.setIssuer(ISSUER)
|
||||
.claim(AUTHORITIES, JSON.toJSONString(new ArrayList<>()))//自定义属性 权限
|
||||
.setExpiration(new Date(System.currentTimeMillis() + securityProperties.getJwtExpiration()))
|
||||
.signWith(SignatureAlgorithm.HS512, securityProperties.getJwtSecret())
|
||||
.compact();
|
||||
token = securityProperties.getJwtTokenPrefix() + token;
|
||||
return token;
|
||||
}
|
||||
|
||||
public boolean validateToken(String token){
|
||||
Claims claims = parser(token);
|
||||
if (MapUtil.isEmpty(claims)){
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
public AuthPrincipalVo parserToUser(String token){
|
||||
String subject = parser(token).getSubject();
|
||||
if(StrUtil.isNotEmpty(subject)){
|
||||
return JSONObject.parseObject(subject, AuthPrincipalVo.class);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public Claims parser(String token) {
|
||||
token = token.replaceAll(securityProperties.getJwtTokenPrefix(),"");
|
||||
return Jwts.parser().setSigningKey(securityProperties.getJwtSecret()).parseClaimsJws(token).getBody();
|
||||
}
|
||||
}
|
||||
package com.ai.da.common.security.jwt;
|
||||
|
||||
import cn.hutool.core.map.MapUtil;
|
||||
import cn.hutool.core.util.StrUtil;
|
||||
import cn.hutool.crypto.digest.DigestUtil;
|
||||
import com.ai.da.common.constant.CommonConstant;
|
||||
import com.ai.da.common.security.config.SecurityProperties;
|
||||
import com.ai.da.model.vo.AuthPrincipalVo;
|
||||
import com.alibaba.fastjson.JSON;
|
||||
import com.alibaba.fastjson.JSONObject;
|
||||
import io.jsonwebtoken.Claims;
|
||||
import io.jsonwebtoken.Jwts;
|
||||
import io.jsonwebtoken.security.Keys;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import jakarta.annotation.Resource;
|
||||
import javax.crypto.SecretKey;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Date;
|
||||
|
||||
/**
|
||||
* @author: dangweijian
|
||||
* @description: JWT工具
|
||||
* @create: 2020-07-09 09:27
|
||||
**/
|
||||
@Slf4j
|
||||
@Component
|
||||
public class JWTTokenHelper {
|
||||
|
||||
@Resource
|
||||
private SecurityProperties securityProperties;
|
||||
|
||||
private static final String ISSUER = "DWJ";
|
||||
private static final String AUTHORITIES = "authorities";
|
||||
private static final String CHANGE_MAILBOX = "changeMailbox";
|
||||
|
||||
public String createToken(AuthPrincipalVo principal) {
|
||||
SecretKey key = buildSigningKey();
|
||||
String token = Jwts.builder()
|
||||
.id(String.valueOf(principal.getId()))
|
||||
.subject(JSONObject.toJSONString(principal))
|
||||
.issuedAt(new Date())
|
||||
.issuer(ISSUER)
|
||||
.claim(AUTHORITIES, JSON.toJSONString(new ArrayList<>()))//自定义属性 权限
|
||||
.expiration(new Date(System.currentTimeMillis() + securityProperties.getJwtExpiration()))
|
||||
.signWith(key)
|
||||
.compact();
|
||||
token = securityProperties.getJwtTokenPrefix() + token;
|
||||
return token;
|
||||
}
|
||||
|
||||
public boolean validateToken(String token) {
|
||||
Claims claims = parser(token);
|
||||
if (MapUtil.isEmpty(claims)) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
public AuthPrincipalVo parserToUser(String token) {
|
||||
String subject = parser(token).getSubject();
|
||||
if (StrUtil.isNotEmpty(subject)) {
|
||||
return JSONObject.parseObject(subject, AuthPrincipalVo.class);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public Claims parser(String token) {
|
||||
token = token.replaceAll(securityProperties.getJwtTokenPrefix(), "");
|
||||
SecretKey key = buildSigningKey();
|
||||
return Jwts.parser()
|
||||
.verifyWith(key)
|
||||
.build()
|
||||
.parseSignedClaims(token)
|
||||
.getPayload();
|
||||
}
|
||||
|
||||
public String createToken(Long userId, String userEmail){
|
||||
SecretKey key = buildSigningKey();
|
||||
String token = Jwts.builder()
|
||||
.id(String.valueOf(userId))
|
||||
.subject(userEmail + "_" + userId)
|
||||
.issuedAt(new Date())
|
||||
.issuer(ISSUER)
|
||||
.claim(CHANGE_MAILBOX, JSON.toJSONString(new ArrayList<>()))//自定义属性 权限
|
||||
.expiration(new Date(System.currentTimeMillis() + CommonConstant.CHANGE_MAILBOX_LINK_VALIDITY))
|
||||
.signWith(key)
|
||||
.compact();
|
||||
return token;
|
||||
}
|
||||
|
||||
public String parseToEmailAndId(String token) {
|
||||
return parser(token).getSubject();
|
||||
}
|
||||
|
||||
/**
|
||||
* JWT 要求 HMAC-SHA 的密钥至少 256 bit,这里统一扩展/哈希密钥长度避免 WeakKeyException。
|
||||
*/
|
||||
private SecretKey buildSigningKey() {
|
||||
byte[] raw = securityProperties.getJwtSecret().getBytes(StandardCharsets.UTF_8);
|
||||
if (raw.length < 32) {
|
||||
raw = DigestUtil.sha256(raw);
|
||||
}
|
||||
return Keys.hmacShaKeyFor(raw);
|
||||
}
|
||||
}
|
||||
|
||||
102
src/main/java/com/ai/da/common/task/AccountTask.java
Normal file
102
src/main/java/com/ai/da/common/task/AccountTask.java
Normal file
@@ -0,0 +1,102 @@
|
||||
package com.ai.da.common.task;
|
||||
|
||||
import com.ai.da.common.utils.RedisUtil;
|
||||
import com.ai.da.mapper.primary.entity.Account;
|
||||
import com.ai.da.service.AccountService;
|
||||
import com.ai.da.service.SubscriptionPlanService;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.scheduling.annotation.Scheduled;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import jakarta.annotation.Resource;
|
||||
import java.util.List;
|
||||
|
||||
@Component
|
||||
@Slf4j
|
||||
public class AccountTask {
|
||||
|
||||
@Resource
|
||||
private AccountService accountService;
|
||||
@Resource
|
||||
private RedisUtil redisUtil;
|
||||
@Resource
|
||||
private SubscriptionPlanService subscriptionPlanService;
|
||||
|
||||
/**
|
||||
* 每周日晚上刷新 年付用户、月付用户的积分
|
||||
* 替换为
|
||||
* 每个月月初只刷新教育子账号的积分
|
||||
*/
|
||||
// @Scheduled(cron = "0 25 14 * * ?")
|
||||
@Scheduled(cron = "0 0 0 1 * ?")
|
||||
public void refreshCreditsMonthly() {
|
||||
log.info("每月1号0点 重置教育版子账号为默认积分");
|
||||
accountService.refreshCreditsMonthly();
|
||||
}
|
||||
|
||||
// @Scheduled(cron = "0 */5 * * * *") // Run every 5 minutes
|
||||
public void getPaidUser() {
|
||||
// 获取code-create 表中 指定日期之后 订单状态为wc-processing的订单
|
||||
accountService.extendValidityForCC();
|
||||
}
|
||||
|
||||
// 每天凌晨0点执行一次 目前已没有角色类型为4的用户
|
||||
/*@Scheduled(cron = "0 0 0 * * ?")
|
||||
public void cancelActivityBenefits() {
|
||||
// 1、查询当前所有参与了活动且过期的用户
|
||||
List<Account> accountList = accountService.getExpiredUserBySystemUser(4);
|
||||
|
||||
// 2、将到期用户置为游客
|
||||
for (Account account : accountList) {
|
||||
log.info("参与活动的用户{} : {} 于 {} 账号有效期到期,置为游客", account.getId(), account.getUserEmail(), account.getValidEndTime());
|
||||
accountService.toVisitor(account);
|
||||
}
|
||||
}*/
|
||||
|
||||
// 每天检测正式用户到期情况,每天凌晨0点执行
|
||||
@Scheduled(cron = "0 0 0 * * ?")
|
||||
public void paidUserToVisitor() {
|
||||
// 1、查询当前已过期正式用户或试用用户
|
||||
List<Account> accountList = accountService.getExpiredUserBySystemUser(1);
|
||||
accountList.addAll(accountService.getExpiredUserBySystemUser(2));
|
||||
accountList.addAll(accountService.getExpiredUserBySystemUser(3));
|
||||
|
||||
// 2、将到期用户置为游客
|
||||
for (Account account : accountList) {
|
||||
log.info("用户{} : {} 于 {}账号有效期到期,置为游客", account.getId(), account.getUserEmail(), account.getValidEndTime());
|
||||
accountService.toVisitor(account);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* !!关闭此定时器!!不再从Code-Create上默认创建AiDA游客
|
||||
* 将Code-Create上注册的用户添加为AiDA的游客
|
||||
*/
|
||||
// @Scheduled(cron = "0 */5 * * * *") // Run every 5 minutes
|
||||
public void registerUserToVisitor() {
|
||||
accountService.registerUserToVisitor();
|
||||
}
|
||||
|
||||
@Scheduled(cron = "0 0 0 1 * ?")
|
||||
// 每月初刷新所有用户用户名剩余修改次数
|
||||
public void resetUsernameModifyTimes(){
|
||||
log.info("重置所有用户的用户名修改次数");
|
||||
redisUtil.batchDeleteKeysWithSamePrefix(RedisUtil.NICKNAME_MODIFY_TIMES);
|
||||
}
|
||||
|
||||
// @Scheduled(cron = "0 35 14 * * ?")
|
||||
@Scheduled(cron = "0 5 0 * * ?")
|
||||
public void checkEduAdminExpireStatus() {
|
||||
accountService.checkEduAdminExpireStatus();
|
||||
}
|
||||
|
||||
@Scheduled(cron = "0 5 0 * * ?")
|
||||
public void activeSubscriptionPlan() {
|
||||
subscriptionPlanService.activeSubscriptionPlan(null);
|
||||
}
|
||||
|
||||
@Scheduled(cron = "0 */5 * * * *") // Run every 5 minutes
|
||||
public void expireSubscription() {
|
||||
subscriptionPlanService.expireSubscription();
|
||||
}
|
||||
}
|
||||
140
src/main/java/com/ai/da/common/task/GenerateTask.java
Normal file
140
src/main/java/com/ai/da/common/task/GenerateTask.java
Normal file
@@ -0,0 +1,140 @@
|
||||
package com.ai.da.common.task;
|
||||
|
||||
import com.ai.da.common.config.exception.BusinessException;
|
||||
import com.ai.da.common.utils.DateUtil;
|
||||
import com.ai.da.mapper.primary.PoseTransformationMapper;
|
||||
import com.ai.da.mapper.primary.ToProductImageResultMapper;
|
||||
import com.ai.da.mapper.primary.entity.*;
|
||||
import com.ai.da.model.vo.PoseTransformationVO;
|
||||
import com.ai.da.service.*;
|
||||
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
|
||||
import io.netty.util.internal.StringUtil;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.scheduling.annotation.Scheduled;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
|
||||
import static com.ai.da.common.enums.CreditsEventsEnum.TO_PRODUCT_IMAGE;
|
||||
|
||||
@Slf4j
|
||||
@Component
|
||||
@RequiredArgsConstructor
|
||||
public class GenerateTask {
|
||||
private final APIGenerateService apiGenerateService;
|
||||
private final CreditsService creditsService;
|
||||
private final GenerateService generateService;
|
||||
private final PoseTransformationMapper poseTransformationMapper;
|
||||
private final ToProductImageResultMapper toProductImageResultMapper;
|
||||
|
||||
|
||||
/*
|
||||
* 对于使用了第三方api的允许异步获得结果的生成功能,可能在第三方接口的结果Ready时没有及时存储结果,导致第三方链接失效
|
||||
* 万相 24h失效,
|
||||
* flux 10mins失效 (使用了flux接口的功能 ToProductImage || Relight, Pattern这里不做补偿)
|
||||
* 故这里通过定时任务做补偿
|
||||
* flux五分钟查询一次,万相1小时查询一次
|
||||
*/
|
||||
@Scheduled(cron = "0 */4 * * * ?")
|
||||
public void fluxCompensationMechanism(){
|
||||
// 1、查所有 任务还没成功、还没失败,正在等待或者执行中的任务id有哪些
|
||||
// (由于获取结果的polling_url在redis中只存一天,大部分结果超过一天之后就无法再找到任务,小部分可以通过公共路径查到结果)
|
||||
List<APIGenerate> apiGenerates = apiGenerateService.getPendingTaskByStatus("flux");
|
||||
if (apiGenerates != null && !apiGenerates.isEmpty()){
|
||||
for (APIGenerate apiGenerate : apiGenerates){
|
||||
String taskId = apiGenerate.getTaskId();
|
||||
// 1. 根据taskId查toProductImageResult, 判断当前任务状态与超时状态
|
||||
ToProductImageResult toProductImageResult = toProductImageResultMapper.selectOne(new QueryWrapper<ToProductImageResult>().eq("task_id", taskId));
|
||||
if (Objects.nonNull(toProductImageResult) && "Pending".equals(toProductImageResult.getStatus())){
|
||||
// 判断当前任务的超时状态
|
||||
if (!DateUtil.isMoreThanOneDayApart(toProductImageResult.getCreateTime())){
|
||||
// 1. 未超时,获取当前任务结果
|
||||
String fileName = toProductImageResult.getResultType().equals(TO_PRODUCT_IMAGE.getName()) ? "product_image" : "relight_image";
|
||||
String objectName = apiGenerate.getAccountId() + "/" + fileName +"/" + taskId + ".png";
|
||||
String fluxResult = generateService.getFluxResult(taskId, objectName);
|
||||
|
||||
// 2. 成功,获取结果,下载图片,上传至minio,更新toProductImageResult表
|
||||
if (StringUtil.isNullOrEmpty(fluxResult) || fluxResult.equals("Fail")){
|
||||
toProductImageResult.setStatus("Fail");
|
||||
toProductImageResultMapper.updateById(toProductImageResult);
|
||||
|
||||
apiGenerate.setStatus("Fail");
|
||||
apiGenerate.setUpdateTime(LocalDateTime.now());
|
||||
apiGenerateService.updateById(apiGenerate);
|
||||
} else if (!fluxResult.equals("Pending")){
|
||||
if (StringUtil.isNullOrEmpty(toProductImageResult.getUrl())){
|
||||
toProductImageResult.setStatus("Success");
|
||||
toProductImageResult.setUrl(fluxResult);
|
||||
toProductImageResultMapper.updateById(toProductImageResult);
|
||||
|
||||
apiGenerate.setStatus("Success");
|
||||
apiGenerate.setUpdateTime(LocalDateTime.now());
|
||||
apiGenerateService.updateById(apiGenerate);
|
||||
}
|
||||
// 扣积分
|
||||
Boolean flag = creditsService.taskCreditsDeduction(apiGenerate.getAccountId(), taskId);
|
||||
if (flag) creditsService.updateChangedCredits(String.valueOf(apiGenerate.getAccountId()), taskId);
|
||||
}
|
||||
} else {
|
||||
// 超时,设置状态为失败
|
||||
toProductImageResult.setStatus("Fail");
|
||||
toProductImageResultMapper.updateById(toProductImageResult);
|
||||
|
||||
apiGenerate.setStatus("Fail");
|
||||
apiGenerate.setUpdateTime(LocalDateTime.now());
|
||||
apiGenerateService.updateById(apiGenerate);
|
||||
}
|
||||
// 将积分暂扣区的积分移除
|
||||
if (toProductImageResult.getStatus().equals("Fail")){
|
||||
creditsService.deleteCreditsDeduction(apiGenerate.getAccountId(), taskId);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// 万相 -> pose transformation 补偿 当前任务执行完后,5分钟再执行一次(不会出现任务重叠的情况)
|
||||
@Scheduled(fixedDelay = 5 * 60 * 1000)
|
||||
public void wxCompensationMechanism(){
|
||||
List<APIGenerate> apiGenerates = apiGenerateService.getPendingTaskByStatus("wx");
|
||||
if (apiGenerates != null && !apiGenerates.isEmpty()){
|
||||
log.info("=====万相补偿获取结果开始=====");
|
||||
for (APIGenerate apiGenerate : apiGenerates){
|
||||
String taskId = apiGenerate.getTaskId();
|
||||
PoseTransformation poseTransformation = poseTransformationMapper.selectOne(new QueryWrapper<PoseTransformation>().eq("unique_id", taskId));
|
||||
if (Objects.nonNull(poseTransformation) && ("Pending".equals(poseTransformation.getTaskStatus()) || "Executing".equals(poseTransformation.getTaskStatus()))){
|
||||
// 判断当前任务的超时状态
|
||||
if (!DateUtil.isMoreThanOneDayApart(poseTransformation.getCreateTime())){
|
||||
try {
|
||||
// 方法中已经完成了pose_transformation和api_generate表的更新,不用额外做处理
|
||||
PoseTransformationVO animateResult = generateService.getAnimateResult(taskId);
|
||||
if (animateResult.getStatus().equals("Success")){
|
||||
log.info("补偿获取结果成功,发送系统消息");
|
||||
}
|
||||
} catch (BusinessException e){
|
||||
log.warn("万相 animation 生成失败,原因:{}", e.getMessage());
|
||||
}
|
||||
}
|
||||
} else {
|
||||
poseTransformation.setTaskStatus("Fail");
|
||||
poseTransformation.setUpdateTime(LocalDateTime.now());
|
||||
poseTransformationMapper.updateById(poseTransformation);
|
||||
|
||||
apiGenerate.setStatus("Fail");
|
||||
apiGenerate.setUpdateTime(LocalDateTime.now());
|
||||
apiGenerateService.updateById(apiGenerate);
|
||||
generateService.sendSysMsgForPT(poseTransformation);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
}
|
||||
216
src/main/java/com/ai/da/common/task/MoveDataScheduler.java
Normal file
216
src/main/java/com/ai/da/common/task/MoveDataScheduler.java
Normal file
@@ -0,0 +1,216 @@
|
||||
//package com.ai.da.common.task;
|
||||
//
|
||||
//import com.ai.da.common.utils.CopyUtil;
|
||||
//import com.ai.da.common.utils.ExcelReader;
|
||||
//import com.ai.da.common.utils.MinioUtil;
|
||||
//import com.ai.da.common.utils.SendEmailUtil;
|
||||
//import com.ai.da.mapper.primary.*;
|
||||
//import com.ai.da.mapper.primary.entity.*;
|
||||
//import com.ai.da.mapper.secondary.AttributeRetrievalMapper;
|
||||
//import com.ai.da.mapper.third.*;
|
||||
//import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
|
||||
//import org.apache.commons.lang3.StringUtils;
|
||||
//import org.apache.poi.ss.usermodel.Row;
|
||||
//import org.apache.poi.ss.usermodel.Sheet;
|
||||
//import org.apache.poi.ss.usermodel.Workbook;
|
||||
//import org.apache.poi.xssf.usermodel.XSSFWorkbook;
|
||||
//import org.springframework.stereotype.Component;
|
||||
//import org.springframework.util.CollectionUtils;
|
||||
//
|
||||
//import jakarta.annotation.PostConstruct;
|
||||
//import jakarta.annotation.Resource;
|
||||
//import java.io.FileOutputStream;
|
||||
//import java.io.IOException;
|
||||
//import java.nio.file.Files;
|
||||
//import java.nio.file.Paths;
|
||||
//import java.time.LocalDate;
|
||||
//import java.time.format.DateTimeFormatter;
|
||||
//import java.util.List;
|
||||
//import java.util.concurrent.ExecutorService;
|
||||
//import java.util.concurrent.Executors;
|
||||
//import java.util.concurrent.TimeUnit;
|
||||
//import java.util.stream.Collectors;
|
||||
//
|
||||
//@Component
|
||||
//public class MoveDataScheduler {
|
||||
//
|
||||
// @PostConstruct
|
||||
// public void test() {
|
||||
// moveData();
|
||||
// }
|
||||
//
|
||||
// @Resource
|
||||
// private UserLikeGroupMapper userLikeGroupMapper;
|
||||
// @Resource
|
||||
// private UserLikeGroupZSMapper userLikeGroupZSMapper;
|
||||
// @Resource
|
||||
// private UserLikeMapper userLikeMapper;
|
||||
// @Resource
|
||||
// private UserLikeZSMapper userLikeZSMapper;
|
||||
// @Resource
|
||||
// private CollectionElementMapper collectionElementMapper;
|
||||
// @Resource
|
||||
// private CollectionElementZSMapper collectionElementZSMapper;
|
||||
//
|
||||
// @Resource
|
||||
// private CollectionMapper collectionMapper;
|
||||
//
|
||||
// @Resource
|
||||
// private CollectionZSMapper collectionZSMapper;
|
||||
//
|
||||
// @Resource
|
||||
// private DesignMapper designMapper;
|
||||
//
|
||||
// @Resource
|
||||
// private DesignZSMapper designZSMapper;
|
||||
//
|
||||
// @Resource
|
||||
// private DesignItemMapper designItemMapper;
|
||||
//
|
||||
// @Resource
|
||||
// private DesignItemZSMapper designItemZSMapper;
|
||||
//
|
||||
// @Resource
|
||||
// private TDesignPythonOutfitMapper designPythonOutfitMapper;
|
||||
//
|
||||
// @Resource
|
||||
// private TDesignPythonOutfitZSMapper designPythonOutfitZSMapper;
|
||||
//
|
||||
// @Resource
|
||||
// private TDesignPythonOutfitDetailMapper designPythonOutfitDetailMapper;
|
||||
//
|
||||
// @Resource
|
||||
// private TDesignPythonOutfitDetailZSMapper designPythonOutfitDetailZSMapper;
|
||||
//
|
||||
// @Resource
|
||||
// private DesignItemDetailMapper designItemDetailMapper;
|
||||
// @Resource
|
||||
// private DesignItemZSDetailMapper designItemDetailZSMapper;
|
||||
//
|
||||
// @Resource
|
||||
// private DesignItemDetailPrintMapper designItemDetailPrintMapper;
|
||||
//
|
||||
// @Resource
|
||||
// private DesignItemDetailPrintZSMapper designItemDetailPrintZSMapper;
|
||||
//
|
||||
//
|
||||
// private void moveData() {
|
||||
// // 查询用户所有history记录
|
||||
// QueryWrapper<UserLikeGroup> userLikeGroupQueryWrapper = new QueryWrapper<>();
|
||||
// userLikeGroupQueryWrapper.lambda().eq(UserLikeGroup::getAccountId, 11411);
|
||||
// List<UserLikeGroup> userLikeGroupList = userLikeGroupMapper.selectList(userLikeGroupQueryWrapper);
|
||||
//
|
||||
// for (UserLikeGroup userLikeGroup : userLikeGroupList) {
|
||||
//
|
||||
// com.ai.da.mapper.third.entity.UserLikeGroup userLikeGroupZS = CopyUtil.copyObject(userLikeGroup, com.ai.da.mapper.third.entity.UserLikeGroup.class);
|
||||
// userLikeGroupZS.setAccountId(11420L);
|
||||
// userLikeGroupZS.setId(null);
|
||||
// Collection collection = collectionMapper.selectById(userLikeGroup.getCollectionId());
|
||||
// com.ai.da.mapper.third.entity.Collection collectionZS = CopyUtil.copyObject(collection, com.ai.da.mapper.third.entity.Collection.class);
|
||||
// collectionZS.setAccountId(11420L);
|
||||
// collectionZS.setId(null);
|
||||
//
|
||||
// if (collection.getMoodTemplateId() != null) {
|
||||
// CollectionElement element = collectionElementMapper.selectById(collection.getMoodTemplateId());
|
||||
// com.ai.da.mapper.third.entity.CollectionElement collectionElementZS = CopyUtil.copyObject(element, com.ai.da.mapper.third.entity.CollectionElement.class);
|
||||
// collectionElementZS.setAccountId(11420L);
|
||||
// collectionElementZS.setId(null);
|
||||
// collectionElementZSMapper.insert(collectionElementZS);
|
||||
// collectionZS.setMoodTemplateId(String.valueOf(collectionElementZS.getId()));
|
||||
// }
|
||||
// collectionZSMapper.insert(collectionZS);
|
||||
// userLikeGroupZS.setCollectionId(collectionZS.getId());
|
||||
// userLikeGroupZSMapper.insert(userLikeGroupZS);
|
||||
//
|
||||
// // 生成元素
|
||||
// QueryWrapper<CollectionElement> collectionElementQueryWrapper = new QueryWrapper<>();
|
||||
// collectionElementQueryWrapper.lambda().eq(CollectionElement::getCollectionId, userLikeGroup.getCollectionId());
|
||||
// List<CollectionElement> collectionElements = collectionElementMapper.selectList(collectionElementQueryWrapper);
|
||||
//
|
||||
// for (CollectionElement collectionElement : collectionElements) {
|
||||
// com.ai.da.mapper.third.entity.CollectionElement collectionElementZS = CopyUtil.copyObject(collectionElement, com.ai.da.mapper.third.entity.CollectionElement.class);
|
||||
// collectionElementZS.setId(null);
|
||||
// collectionElementZS.setAccountId(11420L);
|
||||
// collectionElementZS.setCollectionId(collectionZS.getId());
|
||||
// collectionElementZSMapper.insert(collectionElementZS);
|
||||
// }
|
||||
//
|
||||
// // 查询记录关联
|
||||
// QueryWrapper<UserLike> userLikeQueryWrapper = new QueryWrapper<>();
|
||||
// userLikeQueryWrapper.lambda().eq(UserLike::getUserLikeGroupId, userLikeGroup.getId());
|
||||
// List<UserLike> userLikes = userLikeMapper.selectList(userLikeQueryWrapper);
|
||||
// for (UserLike userLike : userLikes) {
|
||||
// Design design = designMapper.selectById(userLike.getDesignId());
|
||||
// com.ai.da.mapper.third.entity.Design designZS = CopyUtil.copyObject(design, com.ai.da.mapper.third.entity.Design.class);
|
||||
// designZS.setId(null);
|
||||
// designZS.setAccountId(11420L);
|
||||
// designZS.setCollectionId(collectionZS.getId());
|
||||
// designZSMapper.insert(designZS);
|
||||
//
|
||||
// com.ai.da.mapper.third.entity.UserLike userLikeZS = CopyUtil.copyObject(userLike, com.ai.da.mapper.third.entity.UserLike.class);
|
||||
//// Design design = designMapper.selectById(userLike.getDesignId());
|
||||
// userLikeZS.setId(null);
|
||||
// DesignItem designItem = designItemMapper.selectById(userLike.getDesignItemId());
|
||||
// com.ai.da.mapper.third.entity.DesignItem designItemZS = CopyUtil.copyObject(designItem, com.ai.da.mapper.third.entity.DesignItem.class);
|
||||
// designItemZS.setId(null);
|
||||
// designItemZS.setAccountId(11420L);
|
||||
// designItemZS.setDesignId(designZS.getId());
|
||||
// designItemZSMapper.insert(designItemZS);
|
||||
//
|
||||
// QueryWrapper<DesignItemDetail> designItemDetailQueryWrapper = new QueryWrapper<>();
|
||||
// designItemDetailQueryWrapper.lambda().eq(DesignItemDetail::getDesignItemId, designItem.getId());
|
||||
// List<DesignItemDetail> designItemDetails = designItemDetailMapper.selectList(designItemDetailQueryWrapper);
|
||||
// for (DesignItemDetail designItemDetail : designItemDetails) {
|
||||
// com.ai.da.mapper.third.entity.DesignItemDetail designItemDetailZS = CopyUtil.copyObject(designItemDetail, com.ai.da.mapper.third.entity.DesignItemDetail.class);
|
||||
// designItemDetailZS.setId(null);
|
||||
// designItemDetailZS.setDesignItemId(designItemZS.getId());
|
||||
// designItemDetailZS.setAccountId(11420L);
|
||||
// designItemDetailZS.setDesignId(designZS.getId());
|
||||
// designItemDetailZSMapper.insert(designItemDetailZS);
|
||||
//
|
||||
// QueryWrapper<DesignItemDetailPrint> designItemDetailPrintQueryWrapper = new QueryWrapper<>();
|
||||
// designItemDetailPrintQueryWrapper.lambda().eq(DesignItemDetailPrint::getDesignItemDetailId, designItemDetail.getId());
|
||||
// List<DesignItemDetailPrint> designItemDetailPrintList = designItemDetailPrintMapper.selectList(designItemDetailPrintQueryWrapper);
|
||||
// if (!CollectionUtils.isEmpty(designItemDetailPrintList)) {
|
||||
// for (DesignItemDetailPrint designItemDetailPrint : designItemDetailPrintList) {
|
||||
// com.ai.da.mapper.third.entity.DesignItemDetailPrint designItemDetailPrintZS = CopyUtil.copyObject(designItemDetailPrint, com.ai.da.mapper.third.entity.DesignItemDetailPrint.class);
|
||||
// designItemDetailPrintZS.setId(null);
|
||||
// designItemDetailPrintZS.setDesignItemDetailId(designItemDetailZS.getId());
|
||||
// designItemDetailPrintZSMapper.insert(designItemDetailPrintZS);
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// userLikeZS.setDesignItemId(designItemZS.getId());
|
||||
// TDesignPythonOutfit tDesignPythonOutfit = designPythonOutfitMapper.selectById(userLike.getDesignOutfitId());
|
||||
// com.ai.da.mapper.third.entity.TDesignPythonOutfit tDesignPythonOutfitZS = CopyUtil.copyObject(tDesignPythonOutfit, com.ai.da.mapper.third.entity.TDesignPythonOutfit.class);
|
||||
// tDesignPythonOutfitZS.setId(null);
|
||||
// tDesignPythonOutfitZS.setDesignItemId(designItemZS.getId());
|
||||
// tDesignPythonOutfitZS.setCollectionId(collectionZS.getId());
|
||||
// tDesignPythonOutfitZS.setUserId(11420L);
|
||||
// tDesignPythonOutfitZS.setDesignId(designZS.getId());
|
||||
// designPythonOutfitZSMapper.insert(tDesignPythonOutfitZS);
|
||||
//
|
||||
// userLikeZS.setUserLikeGroupId(userLikeGroupZS.getId());
|
||||
// userLikeZS.setDesignId(designZS.getId());
|
||||
// userLikeZS.setDesignOutfitId(tDesignPythonOutfitZS.getId());
|
||||
// userLikeZSMapper.insert(userLikeZS);
|
||||
//
|
||||
// QueryWrapper<TDesignPythonOutfitDetail> designPythonOutfitDetailQueryWrapper = new QueryWrapper<>();
|
||||
// designPythonOutfitDetailQueryWrapper.lambda().eq(TDesignPythonOutfitDetail::getDesignPythonOutfitId, tDesignPythonOutfit.getId());
|
||||
// List<TDesignPythonOutfitDetail> tDesignPythonOutfitDetails = designPythonOutfitDetailMapper.selectList(designPythonOutfitDetailQueryWrapper);
|
||||
// for (TDesignPythonOutfitDetail tDesignPythonOutfitDetail : tDesignPythonOutfitDetails) {
|
||||
// com.ai.da.mapper.third.entity.TDesignPythonOutfitDetail tDesignPythonOutfitDetailZS = CopyUtil.copyObject(tDesignPythonOutfitDetail, com.ai.da.mapper.third.entity.TDesignPythonOutfitDetail.class);
|
||||
// tDesignPythonOutfitDetailZS.setDesignPythonOutfitId(tDesignPythonOutfitZS.getId());
|
||||
// tDesignPythonOutfitDetailZS.setId(null);
|
||||
// tDesignPythonOutfitDetailZS.setDesignId(designZS.getId());
|
||||
// designPythonOutfitDetailZSMapper.insert(tDesignPythonOutfitDetailZS);
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
//
|
||||
//
|
||||
// }
|
||||
//
|
||||
//
|
||||
//}
|
||||
129
src/main/java/com/ai/da/common/task/PaymentTask.java
Normal file
129
src/main/java/com/ai/da/common/task/PaymentTask.java
Normal file
@@ -0,0 +1,129 @@
|
||||
package com.ai.da.common.task;
|
||||
|
||||
import com.ai.da.common.enums.PayTypeEnum;
|
||||
import com.ai.da.mapper.primary.entity.OrderInfo;
|
||||
import com.ai.da.service.*;
|
||||
import com.paypal.http.exceptions.SerializeException;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.scheduling.annotation.Scheduled;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import jakarta.annotation.Resource;
|
||||
import java.time.LocalDate;
|
||||
import java.util.List;
|
||||
|
||||
@Slf4j
|
||||
@Component
|
||||
public class PaymentTask {
|
||||
|
||||
@Resource
|
||||
private OrderInfoService orderInfoService;
|
||||
|
||||
@Resource
|
||||
private StripeService stripeService;
|
||||
|
||||
@Resource
|
||||
private AffiliateService affiliateService;
|
||||
|
||||
// 考虑删除该定时任务(原因:之后的订单列允许用户查看发票,发票未过期时仍可以支付,所以不需要手动使订单过期)
|
||||
// @Scheduled(cron = "0/30 * * * * ?")
|
||||
public void orderConfirmForStripe() throws SerializeException {
|
||||
|
||||
// 查看超过30分钟以上仍未支付的订单 置为超时订单
|
||||
List<OrderInfo> orderInfoList = orderInfoService.getNoPayOrderByDuration(30, PayTypeEnum.STRIPE.getType());
|
||||
|
||||
for (OrderInfo orderInfo : orderInfoList) {
|
||||
String orderNo = orderInfo.getOrderNo();
|
||||
log.warn("超时订单 ===> {}", orderNo);
|
||||
|
||||
//核实订单状态:调用支付宝查单接口
|
||||
stripeService.checkOrderStatus(orderNo);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@Resource
|
||||
private PayPalCheckoutService payPalCheckoutService;
|
||||
|
||||
// @Scheduled(cron = "0/30 * * * * ?")
|
||||
public void orderConfirmForPaypal() throws SerializeException {
|
||||
|
||||
// log.info("PayPal orderConfirm 被执行......");
|
||||
|
||||
List<OrderInfo> orderInfoList = orderInfoService.getNoPayOrderByDuration(30, PayTypeEnum.PAYPAL.getType());
|
||||
|
||||
for (OrderInfo orderInfo : orderInfoList) {
|
||||
String orderNo = orderInfo.getOrderNo();
|
||||
log.warn("超时订单 ===> {}", orderNo);
|
||||
|
||||
//核实订单状态:调用支付宝查单接口
|
||||
payPalCheckoutService.checkOrderStatus(orderNo);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@Resource
|
||||
private AliPayService aliPayService;
|
||||
|
||||
/**
|
||||
* 从第0秒开始每隔30秒执行1次,查询创建超过5分钟,并且未支付的订单
|
||||
*/
|
||||
// @Scheduled(cron = "0/30 * * * * ?")
|
||||
public void orderConfirmForAlipay(){
|
||||
/*
|
||||
log.info("Alipay orderConfirm 被执行......");
|
||||
|
||||
List<OrderInfo> orderInfoList = orderInfoService.getNoPayOrderByDuration(5, PayTypeEnum.ALIPAY.getType());
|
||||
|
||||
for (OrderInfo orderInfo : orderInfoList) {
|
||||
String orderNo = orderInfo.getOrderNo();
|
||||
log.warn("超时订单 ===> {}", orderNo);
|
||||
|
||||
//核实订单状态:调用支付宝查单接口
|
||||
aliPayService.checkOrderStatus(orderNo);
|
||||
}*/
|
||||
}
|
||||
|
||||
// !!关闭此定时器,改为提前三天站内信提醒!!
|
||||
// 提前7天向用户发送提醒邮件,每天早上8点执行
|
||||
// @Scheduled(cron = "0 0 8 * * ?")
|
||||
// public void subscriptionReminder(){
|
||||
// stripeService.subscriptionReminder();
|
||||
// }
|
||||
|
||||
|
||||
// 如果有订阅已创建,但是没有发邮件通知的,需要主动获取回调信息并向用户发送邮件
|
||||
public void checkSubscriptionPayment(){
|
||||
//
|
||||
}
|
||||
|
||||
// @Scheduled(cron = "0 */5 * * * *") // Run every 5 minutes
|
||||
public void updateAffiliateInfoWithPayment(){
|
||||
// log.info("佣金计算定时器");
|
||||
affiliateService.updateAffiliateInfoWithPayment();
|
||||
}
|
||||
|
||||
// 定时同步(每分钟一次)
|
||||
@Scheduled(fixedRate = 60000)
|
||||
public void syncLinkViewCountToDB(){
|
||||
affiliateService.syncLinkViewCountToDB();
|
||||
}
|
||||
|
||||
// @Scheduled(cron = "0 0 8 28-31 * ?")
|
||||
public void commissionSummaryReminder(){
|
||||
// 每个月末的最后一天的早上八点执行
|
||||
LocalDate today = LocalDate.now();
|
||||
// 判断是否为月底
|
||||
if (today.plusDays(1).getDayOfMonth() == 1) {
|
||||
log.info("今天是月底,执行佣金结算提醒任务!");
|
||||
affiliateService.commissionCalculation(null, null);
|
||||
}
|
||||
}
|
||||
|
||||
@Scheduled(cron = "0 */5 * * * *") // Run every 5 minutes
|
||||
public void calcCouponsCommission(){
|
||||
// log.info("优惠券佣金计算定时器");
|
||||
affiliateService.calcCouponsCommission();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,144 @@
|
||||
package com.ai.da.common.task;
|
||||
|
||||
import com.ai.da.common.utils.SendEmailUtil;
|
||||
import com.ai.da.mapper.primary.AccountMapper;
|
||||
import com.ai.da.mapper.primary.SubscriptionInfoMapper;
|
||||
import com.ai.da.mapper.primary.entity.Account;
|
||||
import com.ai.da.mapper.primary.entity.SubscriptionInfo;
|
||||
import com.ai.da.service.StripeService;
|
||||
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
|
||||
import io.netty.util.internal.StringUtil;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.scheduling.annotation.Scheduled;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
import java.time.ZoneId;
|
||||
import java.time.ZoneOffset;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
@Slf4j
|
||||
@Component
|
||||
@RequiredArgsConstructor
|
||||
public class SubscriptionReminderTask {
|
||||
|
||||
public final AccountMapper accountMapper;
|
||||
|
||||
public final SubscriptionInfoMapper subscriptionInfoMapper;
|
||||
|
||||
public final StripeService stripeService;
|
||||
|
||||
// 订阅类型与提前天数的映射配置
|
||||
private static final Map<String, Integer> REMINDER_DAYS_CONFIG = new HashMap<>();
|
||||
|
||||
static {
|
||||
REMINDER_DAYS_CONFIG.put("month", 7);
|
||||
REMINDER_DAYS_CONFIG.put("year", 14);
|
||||
}
|
||||
|
||||
// @Scheduled(cron = "0 0 9 * * ?")
|
||||
public void subscriptionReminder() {
|
||||
// 获取所有需要通知的订阅
|
||||
List<SubscriptionInfo> subscriptionInfos = getDueSubscriptions();
|
||||
|
||||
for (SubscriptionInfo subscriptionInfo : subscriptionInfos) {
|
||||
Integer daysBefore = REMINDER_DAYS_CONFIG.get(subscriptionInfo.getType());
|
||||
if (daysBefore == null) {
|
||||
log.warn("未知的订阅类型: {}", subscriptionInfo.getType());
|
||||
continue;
|
||||
}
|
||||
String emailType = subscriptionInfo.getStatus().equals("active") ? "reminder_subscriber" : subscriptionInfo.getStatus().equals("canceled") ? "reminder_expire" : null;
|
||||
if (StringUtil.isNullOrEmpty(emailType)) {
|
||||
log.warn("未知订阅状态:{}", subscriptionInfo.getStatus());
|
||||
continue;
|
||||
}
|
||||
|
||||
boolean success = stripeService.sendEmail(subscriptionInfo.getSubscriptionId(), emailType, subscriptionInfo.getOrderNo());
|
||||
if (success) {
|
||||
log.info("提前{}天向用户 {} 发送续订通知邮件,订阅类型: {}",
|
||||
daysBefore, subscriptionInfo.getAccountId(), subscriptionInfo.getType());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private List<SubscriptionInfo> getDueSubscriptions() {
|
||||
List<SubscriptionInfo> results = new ArrayList<>();
|
||||
|
||||
for (Map.Entry<String, Integer> entry : REMINDER_DAYS_CONFIG.entrySet()) {
|
||||
String subscriptionType = entry.getKey();
|
||||
int daysBefore = entry.getValue();
|
||||
|
||||
results.addAll(getSubscriptionsDueInDays(subscriptionType, daysBefore));
|
||||
}
|
||||
|
||||
return results;
|
||||
}
|
||||
|
||||
private List<SubscriptionInfo> getSubscriptionsDueInDays(String subscriptionType, int daysBefore) {
|
||||
LocalDateTime targetDate = LocalDateTime.now().plusDays(daysBefore);
|
||||
LocalDateTime startOfDay = targetDate.toLocalDate().atStartOfDay();
|
||||
LocalDateTime endOfDay = targetDate.toLocalDate().atTime(23, 59, 59);
|
||||
|
||||
// 使用系统默认时区
|
||||
ZoneId zoneId = ZoneId.systemDefault();
|
||||
long startTimestamp = startOfDay.atZone(zoneId).toEpochSecond();
|
||||
long endTimestamp = endOfDay.atZone(zoneId).toEpochSecond();
|
||||
|
||||
QueryWrapper<SubscriptionInfo> qw = new QueryWrapper<>();
|
||||
qw.lambda().ge(SubscriptionInfo::getCurrentPeriodEnd, startTimestamp);
|
||||
qw.lambda().lt(SubscriptionInfo::getCurrentPeriodEnd, endTimestamp);
|
||||
// qw.eq("status", "active");
|
||||
qw.lambda().eq(SubscriptionInfo::getType, subscriptionType);
|
||||
|
||||
return subscriptionInfoMapper.selectList(qw);
|
||||
}
|
||||
|
||||
// @Scheduled(cron = "0 0 9 * * ?")
|
||||
public void trialReminder() {
|
||||
// 今天的 00:00:00 和 23:59:59
|
||||
LocalDateTime startOfDay = LocalDateTime.now().toLocalDate().atStartOfDay();
|
||||
LocalDateTime endOfDay = LocalDateTime.now().toLocalDate().atTime(23, 59, 59);
|
||||
|
||||
// 使用系统默认时区
|
||||
ZoneId zoneId = ZoneId.systemDefault();
|
||||
long startTimestamp = startOfDay.atZone(zoneId).toEpochSecond() * 1000;
|
||||
long endTimestamp = endOfDay.atZone(zoneId).toEpochSecond() * 1000;
|
||||
|
||||
QueryWrapper<Account> queryWrapper = new QueryWrapper<>();
|
||||
queryWrapper.lambda().gt(Account::getValidEndTime, startTimestamp)
|
||||
.lt(Account::getValidEndTime, endTimestamp)
|
||||
.eq(Account::getSystemUser, 3);
|
||||
|
||||
List<Account> accounts = accountMapper.selectList(queryWrapper);
|
||||
for (Account account : accounts) {
|
||||
String language = stripeService.getLanguage(account.getLanguage(), account.getCountry(), "reminder_trial");
|
||||
SendEmailUtil.subscriptionEmailReminder("reminder_trial", null, language, account.getUserEmail());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* public void subscriptionReminder(){
|
||||
// 提前7天的 00:00:00 和 23:59:59
|
||||
LocalDateTime startOfDay = LocalDateTime.now().plusDays(7).toLocalDate().atStartOfDay();
|
||||
LocalDateTime endOfDay = LocalDateTime.now().plusDays(7).toLocalDate().atTime(23, 59, 59);
|
||||
|
||||
// 转为时间戳
|
||||
long startTimestamp = startOfDay.toEpochSecond(ZoneOffset.UTC);
|
||||
long endTimestamp = endOfDay.toEpochSecond(ZoneOffset.UTC);
|
||||
|
||||
QueryWrapper<SubscriptionInfo> qw = new QueryWrapper<>();
|
||||
qw.ge("current_period_end", startTimestamp);
|
||||
qw.lt("current_period_end", endTimestamp);
|
||||
qw.eq("status", "active");
|
||||
|
||||
List<SubscriptionInfo> subscriptionInfos = subscriptionInfoMapper.selectList(qw);
|
||||
for (SubscriptionInfo subscriptionInfo : subscriptionInfos) {
|
||||
boolean b = sendEmail(subscriptionInfo.getSubscriptionId(), "reminder", null);
|
||||
if (b) log.info("提前7天向用户 {} 发送续订通知邮件", subscriptionInfo.getAccountId());
|
||||
}
|
||||
}*/
|
||||
}
|
||||
@@ -23,16 +23,17 @@ public class AccessLimitUtils {
|
||||
* @param interfaceName
|
||||
* @return
|
||||
*/
|
||||
public static void validate(String interfaceName,Integer count) {
|
||||
Integer useCount= LocalCacheUtils.getAidaInterfaceCurrentLimitingCache(interfaceName);
|
||||
if(useCount >count){
|
||||
public static void validate(String interfaceName, Integer count) {
|
||||
Integer useCount = LocalCacheUtils.getAidaInterfaceCurrentLimitingCache(interfaceName);
|
||||
if (useCount > count) {
|
||||
//系统繁忙
|
||||
throw new BusinessException("system busy !");
|
||||
}else{
|
||||
useCount ++;
|
||||
LocalCacheUtils.setAidaInterfaceCurrentLimitingCache(interfaceName,useCount);
|
||||
throw new BusinessException("system.busy");
|
||||
} else {
|
||||
useCount++;
|
||||
LocalCacheUtils.setAidaInterfaceCurrentLimitingCache(interfaceName, useCount);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 校验过后 接口完毕 去掉限流
|
||||
*
|
||||
@@ -40,9 +41,9 @@ public class AccessLimitUtils {
|
||||
* @return
|
||||
*/
|
||||
public static void validateOut(String interfaceName) {
|
||||
Integer useCount= LocalCacheUtils.getAidaInterfaceCurrentLimitingCache(interfaceName);
|
||||
useCount --;
|
||||
LocalCacheUtils.setAidaInterfaceCurrentLimitingCache(interfaceName,useCount);
|
||||
Integer useCount = LocalCacheUtils.getAidaInterfaceCurrentLimitingCache(interfaceName);
|
||||
useCount--;
|
||||
LocalCacheUtils.setAidaInterfaceCurrentLimitingCache(interfaceName, useCount);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
383
src/main/java/com/ai/da/common/utils/AlipayHKEncryptionUtil.java
Normal file
383
src/main/java/com/ai/da/common/utils/AlipayHKEncryptionUtil.java
Normal file
@@ -0,0 +1,383 @@
|
||||
package com.ai.da.common.utils;
|
||||
|
||||
import cn.hutool.core.io.resource.ClassPathResource;
|
||||
import com.ai.da.model.dto.AlipayHKParametersDTO;
|
||||
import com.ai.da.model.dto.AlipayHKRequestDTO;
|
||||
import com.alibaba.fastjson.JSONObject;
|
||||
import com.google.gson.Gson;
|
||||
import com.google.gson.GsonBuilder;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.bouncycastle.asn1.x509.SubjectPublicKeyInfo;
|
||||
import org.bouncycastle.crypto.digests.SHA256Digest;
|
||||
import org.bouncycastle.crypto.params.AsymmetricKeyParameter;
|
||||
import org.bouncycastle.crypto.signers.RSADigestSigner;
|
||||
import org.bouncycastle.crypto.util.PublicKeyFactory;
|
||||
import org.bouncycastle.openssl.PEMParser;
|
||||
import org.bouncycastle.util.io.pem.PemObject;
|
||||
import org.bouncycastle.util.io.pem.PemReader;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import javax.crypto.*;
|
||||
import javax.crypto.spec.IvParameterSpec;
|
||||
import javax.crypto.spec.SecretKeySpec;
|
||||
import java.io.*;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.security.*;
|
||||
import java.security.spec.PKCS8EncodedKeySpec;
|
||||
import java.security.spec.X509EncodedKeySpec;
|
||||
import java.time.LocalDateTime;
|
||||
import java.time.format.DateTimeFormatter;
|
||||
import java.util.Base64;
|
||||
import java.util.HashMap;
|
||||
import java.util.UUID;
|
||||
|
||||
@Slf4j
|
||||
@Component
|
||||
public class AlipayHKEncryptionUtil {
|
||||
|
||||
@Value("${alipayHK.merchantId}")
|
||||
private String merchantId;
|
||||
|
||||
@Value("${alipayHK.segmentId}")
|
||||
private String segmentId;
|
||||
|
||||
@Value("${alipayHK.AESKey}")
|
||||
private String aesKey;
|
||||
|
||||
@Value("${alipayHK.rsaPrivateKey}")
|
||||
private String privateKeyPath;
|
||||
|
||||
@Value("${alipayHK.rsaPublicKey}")
|
||||
private String publicKeyPath;
|
||||
|
||||
@Value("${alipayHK.CODPublicKey}")
|
||||
private String CODPublicKeyPath;
|
||||
|
||||
|
||||
/**
|
||||
* 加密
|
||||
* @param param
|
||||
* @param serviceName
|
||||
* @return
|
||||
* @throws NoSuchPaddingException
|
||||
* @throws NoSuchAlgorithmException
|
||||
* @throws InvalidAlgorithmParameterException
|
||||
* @throws InvalidKeyException
|
||||
* @throws IllegalBlockSizeException
|
||||
* @throws BadPaddingException
|
||||
* @throws IOException
|
||||
*/
|
||||
public AlipayHKRequestDTO AESCBCWithRSA(HashMap<String, Object> param, String serviceName) throws NoSuchPaddingException, NoSuchAlgorithmException, InvalidAlgorithmParameterException, InvalidKeyException, IllegalBlockSizeException, BadPaddingException, IOException {
|
||||
// Pre-shared secret key, DO NOT hardcode this key
|
||||
String key = aesKey;
|
||||
// The path to the rsa private key file, DO NOT save this key to a publicly accessible location
|
||||
// 使用私钥创建数字签名
|
||||
// Mode, aes-128-cbc for 128bit key
|
||||
// String mode = "aes-128-cbc";
|
||||
String mode = "aes-256-cbc";
|
||||
// Padding mode
|
||||
String padding = "pkcs7";
|
||||
// signature alogrithm
|
||||
String signatureAlgorithm = "rsa-sha256";
|
||||
// String signatureAlgorithm = "SHA256withRSA";
|
||||
// Message body
|
||||
AlipayHKParametersDTO requestMessage = new AlipayHKParametersDTO();
|
||||
requestMessage.setService(serviceName);
|
||||
requestMessage.setMerchant_id(merchantId);
|
||||
requestMessage.setRequest_time(Long.toString(System.currentTimeMillis() / 1000L));
|
||||
requestMessage.setRequest_uuid(UUID.randomUUID().toString());
|
||||
// HashMap<String, Object> param = new HashMap<>();
|
||||
requestMessage.setParameters(param);
|
||||
|
||||
// Serialize message body
|
||||
Gson gson = new GsonBuilder().disableHtmlEscaping().create();
|
||||
String content = gson.toJson(requestMessage);
|
||||
log.info("alipay-hk request 加密前:{}", content);
|
||||
|
||||
// Secure random iv 获取随机种子
|
||||
SecureRandom secureRandom = new SecureRandom();
|
||||
byte[] iv = new byte[16]; //NEVER REUSE THIS IV WITH THE SAME KEY
|
||||
secureRandom.nextBytes(iv);
|
||||
|
||||
// Algorithms
|
||||
String alogrithm = "AES/CBC/PKCS5Padding";
|
||||
|
||||
// 创建 AES 密钥对象
|
||||
SecretKey secretKey = new SecretKeySpec(key.getBytes(), "AES");
|
||||
// 为加密算法提供一个随机的初始化向量,以增强加密安全性
|
||||
IvParameterSpec parameterSpec = new IvParameterSpec(iv);
|
||||
// 创建 Cipher 对象
|
||||
Cipher cipher = Cipher.getInstance(alogrithm);
|
||||
// 初始化为加密模式 Cipher.ENCRYPT_MODE
|
||||
cipher.init(Cipher.ENCRYPT_MODE, secretKey, parameterSpec);
|
||||
|
||||
// Cipher text 对请求内容加密
|
||||
byte[] cipherText = cipher.doFinal(content.getBytes());
|
||||
|
||||
// Concat iv and cipher text for signing
|
||||
ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
|
||||
outputStream.write(iv);
|
||||
outputStream.write(cipherText);
|
||||
byte signMessage[] = outputStream.toByteArray();
|
||||
|
||||
// Sign key 读取rsa私钥文件,解析并得到私钥对象 privateKey
|
||||
String rsaPrivateKeyPath = privateKeyPath;
|
||||
PrivateKey privateKey = null;
|
||||
byte[] signature;
|
||||
try {
|
||||
privateKey = readPrivateKeyFromFile(rsaPrivateKeyPath);
|
||||
Signature signer = Signature.getInstance("SHA256withRSA");
|
||||
signer.initSign(privateKey);
|
||||
// 将加密内容和随机向量均加签
|
||||
signer.update(signMessage);
|
||||
signature = signer.sign();
|
||||
} catch (SignatureException e) {
|
||||
throw new RuntimeException(e);
|
||||
} catch (Exception e) {
|
||||
log.error(e.getMessage());
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
|
||||
Base64.Encoder encoder = Base64.getEncoder();
|
||||
// Combine result
|
||||
AlipayHKRequestDTO alipayHKRequestDTO = new AlipayHKRequestDTO();
|
||||
alipayHKRequestDTO.setMerchant_id(merchantId);
|
||||
alipayHKRequestDTO.setNonce(encoder.encodeToString(iv));
|
||||
alipayHKRequestDTO.setMessage(encoder.encodeToString(cipherText));
|
||||
alipayHKRequestDTO.setTag(encoder.encodeToString(signature));
|
||||
String cipherSuite = mode + "-" + padding + "-with-" + signatureAlgorithm;
|
||||
alipayHKRequestDTO.setCipher_suite(cipherSuite);
|
||||
|
||||
// Encode to json
|
||||
String jsonEncoded = JSONObject.toJSONString(alipayHKRequestDTO);
|
||||
log.info("alipay-hk request 加密加签后:{}",jsonEncoded);
|
||||
|
||||
// String info = AlipayHKRequestUtil.createOrder(alipayHKRequestDTO);
|
||||
// log.info(info);
|
||||
return alipayHKRequestDTO;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* 从文件中读取RSA私钥
|
||||
* @param filePath
|
||||
* @return
|
||||
* @throws Exception
|
||||
*/
|
||||
private static PrivateKey readPrivateKeyFromFile(String filePath) throws Exception {
|
||||
ClassPathResource classPathResource = new ClassPathResource(filePath);
|
||||
InputStream inputstream = classPathResource.getStream();
|
||||
String privateKeyContent = getString(inputstream);
|
||||
|
||||
// 进行 Base64 解码
|
||||
byte[] privateKeyBytes = Base64.getDecoder().decode(privateKeyContent);
|
||||
|
||||
// 根据 PKCS8 格式的私钥字节数组构造私钥对象
|
||||
KeyFactory keyFactory = KeyFactory.getInstance("RSA");
|
||||
PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(privateKeyBytes);
|
||||
return keyFactory.generatePrivate(keySpec);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private static String getString(InputStream inputstream) throws IOException {
|
||||
BufferedReader reader = new BufferedReader(new InputStreamReader(inputstream));
|
||||
// BufferedReader reader = new BufferedReader(new FileReader(filePath));
|
||||
StringBuilder keyBuffer = new StringBuilder();
|
||||
String line;
|
||||
|
||||
// 读取文本文件中的内容
|
||||
while ((line = reader.readLine()) != null) {
|
||||
keyBuffer.append(line);
|
||||
}
|
||||
reader.close();
|
||||
|
||||
// 去除私钥内容中的头部和尾部信息
|
||||
String privateKeyContent = keyBuffer.toString()
|
||||
.replace("-----BEGIN PRIVATE KEY-----", "")
|
||||
.replace("-----END PRIVATE KEY-----", "")
|
||||
.replaceAll("\\s+", ""); // 去除空格、换行等字符
|
||||
return privateKeyContent;
|
||||
}
|
||||
|
||||
/**
|
||||
* 使用 AES 密钥和随机向量进行解密
|
||||
*/
|
||||
public String decryptAES(String encryptedText, String iv) throws Exception {
|
||||
byte[] encryptedBytes = Base64.getDecoder().decode(encryptedText);
|
||||
byte[] ivBytes = Base64.getDecoder().decode(iv);
|
||||
|
||||
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
|
||||
SecretKeySpec secretKeySpec = new SecretKeySpec(aesKey.getBytes(), "AES");
|
||||
IvParameterSpec ivParameterSpec = new IvParameterSpec(ivBytes);
|
||||
|
||||
cipher.init(Cipher.DECRYPT_MODE, secretKeySpec, ivParameterSpec);
|
||||
byte[] decryptedBytes = cipher.doFinal(encryptedBytes);
|
||||
|
||||
return new String(decryptedBytes, StandardCharsets.UTF_8);
|
||||
}
|
||||
|
||||
public void test() throws Exception {
|
||||
// 加密数据
|
||||
AlipayHKParametersDTO requestMessage = new AlipayHKParametersDTO();
|
||||
requestMessage.setService("create_order");
|
||||
requestMessage.setMerchant_id(merchantId);
|
||||
requestMessage.setRequest_time(Long.toString(System.currentTimeMillis() / 1000L));
|
||||
requestMessage.setRequest_uuid(UUID.randomUUID().toString());
|
||||
HashMap<String, Object> param = new HashMap<>();
|
||||
requestMessage.setParameters(param);
|
||||
String orderRef = LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyyMMddHHmmss"));
|
||||
param.put("order_ref", orderRef);
|
||||
param.put("amount", 208.12);
|
||||
param.put("subject", "四月帳單 April Bill");
|
||||
param.put("wallet", "ALIPAYHK");
|
||||
param.put("segment_id", segmentId);
|
||||
param.put("payment_solution", "WAP");
|
||||
Gson gson = new Gson();
|
||||
String plaintext = gson.toJson(requestMessage);
|
||||
System.out.println(plaintext);
|
||||
|
||||
// 生成 AES 密钥
|
||||
String key = aesKey;
|
||||
SecretKey aesKey = new SecretKeySpec(key.getBytes(), "AES");
|
||||
|
||||
// 使用 RSA 公钥加密 AES 密钥
|
||||
String rsaPublicKeyPath = publicKeyPath;
|
||||
PublicKey publicKey = readPublicKey(rsaPublicKeyPath);
|
||||
|
||||
Cipher rsaCipher = Cipher.getInstance("RSA/ECB/PKCS1Padding");
|
||||
// Cipher rsaCipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
|
||||
rsaCipher.init(Cipher.ENCRYPT_MODE, publicKey);
|
||||
byte[] encryptedAesKey = rsaCipher.doFinal(aesKey.getEncoded());
|
||||
|
||||
// 使用 AES-128-CBC 加密数据
|
||||
Cipher aesCipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
|
||||
byte[] ivBytes = generateRandomIV(aesCipher.getBlockSize());
|
||||
IvParameterSpec ivSpec = new IvParameterSpec(ivBytes);
|
||||
|
||||
aesCipher.init(Cipher.ENCRYPT_MODE, aesKey, ivSpec);
|
||||
byte[] encryptedData = aesCipher.doFinal(plaintext.getBytes());
|
||||
|
||||
// 数字签名(使用 RSA 私钥)
|
||||
String rsaPrivateKeyPath = privateKeyPath;
|
||||
PrivateKey privateKey = readPrivateKeyFromFile(rsaPrivateKeyPath);
|
||||
Signature signer = Signature.getInstance("SHA256withRSA");
|
||||
signer.initSign(privateKey);
|
||||
signer.update(encryptedData);
|
||||
byte[] signatureBytes = signer.sign();
|
||||
Base64.Encoder encoder = Base64.getEncoder();
|
||||
|
||||
// 将加密后的数据和签名进行Base64编码
|
||||
String base64EncryptedData = Base64.getEncoder().encodeToString(encryptedData);
|
||||
String base64Signature = Base64.getEncoder().encodeToString(signatureBytes);
|
||||
|
||||
// 输出加密后的数据和签名
|
||||
System.out.println("加密后的数据:" + base64EncryptedData);
|
||||
System.out.println("数字签名:" + base64Signature);
|
||||
|
||||
|
||||
HashMap<String, String> result = new HashMap<String, String>();
|
||||
result.put("merchant_id",merchantId);
|
||||
result.put("nonce", encoder.encodeToString(ivBytes));
|
||||
result.put("message", encoder.encodeToString(encryptedData));
|
||||
result.put("tag", encoder.encodeToString(signatureBytes));
|
||||
|
||||
String mode = "aes-128-cbc";
|
||||
// Padding mode
|
||||
String padding = "pkcs7";
|
||||
// signature alogrithm
|
||||
String signatureAlgorithm = "rsa-sha256";
|
||||
String cipherSuite = mode + "-" + padding + "-with-" + signatureAlgorithm;
|
||||
result.put("cipher_suite", cipherSuite);
|
||||
|
||||
System.out.println("map 格式:" + result);
|
||||
// Encode to json
|
||||
String jsonEncoded = JSONObject.toJSONString(result);
|
||||
System.out.println("json 格式:" + jsonEncoded);
|
||||
|
||||
AlipayHKRequestDTO alipayHKRequestDTO = new AlipayHKRequestDTO();
|
||||
alipayHKRequestDTO.setMerchant_id(merchantId);
|
||||
alipayHKRequestDTO.setNonce(encoder.encodeToString(ivBytes));
|
||||
alipayHKRequestDTO.setMessage(encoder.encodeToString(encryptedData));
|
||||
alipayHKRequestDTO.setTag(encoder.encodeToString(signatureBytes));
|
||||
alipayHKRequestDTO.setCipher_suite(cipherSuite);
|
||||
|
||||
// String info = AlipayHKRequestUtil.createOrder(result);
|
||||
// log.info(info);
|
||||
|
||||
// 解密和验证
|
||||
// byte[] decryptedAesKey = rsaCipher.doFinal(encryptedAesKey);
|
||||
byte[] decryptedAesKey = rsaCipher.doFinal(aesKey.getEncoded());
|
||||
SecretKey decryptedAesSecretKey = new SecretKeySpec(decryptedAesKey, "AES");
|
||||
|
||||
aesCipher.init(Cipher.DECRYPT_MODE, decryptedAesSecretKey, ivSpec);
|
||||
byte[] decryptedData = aesCipher.doFinal(Base64.getDecoder().decode(base64EncryptedData));
|
||||
|
||||
// 验证数字签名
|
||||
Signature verifier = Signature.getInstance("SHA256withRSA");
|
||||
verifier.initVerify(publicKey);
|
||||
verifier.update(decryptedData);
|
||||
boolean signatureValid = verifier.verify(Base64.getDecoder().decode(base64Signature));
|
||||
|
||||
System.out.println("解密后的数据:" + new String(decryptedData));
|
||||
System.out.println("数字签名验证结果:" + signatureValid);
|
||||
}
|
||||
|
||||
// public static PublicKey readPublicKey(File file) throws Exception {
|
||||
public static PublicKey readPublicKey(String fileName) throws Exception {
|
||||
KeyFactory factory = KeyFactory.getInstance("RSA");
|
||||
|
||||
ClassPathResource classPathResource = new ClassPathResource(fileName);
|
||||
InputStream inputStream = classPathResource.getStream();
|
||||
BufferedReader fileReader = new BufferedReader(new InputStreamReader(inputStream));
|
||||
try (PemReader pemReader = new PemReader(fileReader)) {
|
||||
|
||||
PemObject pemObject = pemReader.readPemObject();
|
||||
byte[] content = pemObject.getContent();
|
||||
X509EncodedKeySpec pubKeySpec = new X509EncodedKeySpec(content);
|
||||
return factory.generatePublic(pubKeySpec);
|
||||
}
|
||||
}
|
||||
|
||||
private static byte[] generateRandomIV(int blockSize) {
|
||||
SecureRandom random = new SecureRandom();
|
||||
byte[] iv = new byte[blockSize];
|
||||
random.nextBytes(iv);
|
||||
return iv;
|
||||
}
|
||||
|
||||
public Boolean signatureVerification(String data, String signatureBase64){
|
||||
|
||||
Base64.Decoder decoder = Base64.getDecoder();
|
||||
// Verify key
|
||||
try {
|
||||
ClassPathResource classPathResource = new ClassPathResource(CODPublicKeyPath);
|
||||
InputStream inputstream = classPathResource.getStream();
|
||||
// 从指定的路径读取公钥文件
|
||||
InputStreamReader isrPub = new InputStreamReader(inputstream);
|
||||
PEMParser pemParserPub = new PEMParser(isrPub);
|
||||
// 使用 PEMParser 解析公钥文件
|
||||
SubjectPublicKeyInfo pubInfo = (SubjectPublicKeyInfo) pemParserPub.readObject();
|
||||
// 从 SubjectPublicKeyInfo 创建 AsymmetricKeyParameter 对象
|
||||
AsymmetricKeyParameter pubKey = PublicKeyFactory.createKey(pubInfo);
|
||||
// Verifying; 创建 RSADigestSigner 对象并使用 SHA-256 作为摘要算法
|
||||
RSADigestSigner verifier = new RSADigestSigner(new SHA256Digest());
|
||||
// 初始化 RSADigestSigner,设置为验证模式并提供公钥参数
|
||||
verifier.init(false, pubKey);
|
||||
// 将要验证的数据转换为字节数组
|
||||
byte[] signMessageForVerifying = data.getBytes();
|
||||
// 将 Base64 编码的签名转换为字节数组
|
||||
byte[] signatureBase64ForVerifying = decoder.decode(signatureBase64);
|
||||
// 使用签名器更新要验证的数据
|
||||
verifier.update(signMessageForVerifying, 0, signMessageForVerifying.length);
|
||||
// 验证签名并返回结果
|
||||
Boolean verifyResult = verifier.verifySignature(signatureBase64ForVerifying);
|
||||
return verifyResult;
|
||||
} catch (Exception e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@@ -0,0 +1,62 @@
|
||||
package com.ai.da.common.utils;
|
||||
|
||||
import com.ai.da.common.config.exception.BusinessException;
|
||||
import com.ai.da.model.dto.AlipayHKRequestDTO;
|
||||
import com.alibaba.fastjson.serializer.SerializerFeature;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import okhttp3.*;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.time.Instant;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import com.alibaba.fastjson.JSONObject;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
@Slf4j
|
||||
@Component
|
||||
public class AlipayHKRequestUtil {
|
||||
|
||||
public String requestAlipayHK(AlipayHKRequestDTO alipayHKRequestDTO) {
|
||||
OkHttpClient client = new OkHttpClient().newBuilder()
|
||||
.connectTimeout(30, TimeUnit.SECONDS)
|
||||
.pingInterval(5, TimeUnit.SECONDS)//websocket轮训间隔(单位:秒)
|
||||
.readTimeout(60, TimeUnit.SECONDS)//读取超时(单位:秒)
|
||||
.writeTimeout(60, TimeUnit.SECONDS)//写入超时(单位:秒)
|
||||
.build();
|
||||
MediaType mediaType = MediaType.parse("application/json;charset=utf-8");
|
||||
long epochMilli = Instant.now().toEpochMilli();
|
||||
log.info("Alipay-HK send request unix timestamp: {}", epochMilli);
|
||||
|
||||
String jsonString = JSONObject.toJSONString(alipayHKRequestDTO, SerializerFeature.WriteMapNullValue);
|
||||
// log.info(jsonString);
|
||||
|
||||
RequestBody body = RequestBody.create(mediaType, jsonString);
|
||||
|
||||
Request request = new Request.Builder()
|
||||
// .url("https://aqs-api.sandbox-codpayment.com/v1/service")
|
||||
.url("https://aqs-api.codpayment.com/v1/service")
|
||||
.method("POST", body)
|
||||
.addHeader("Content-Type", "application/json;charset=utf-8")
|
||||
.build();
|
||||
Response response;
|
||||
String bodyString;
|
||||
try {
|
||||
response = client.newCall(request).execute();
|
||||
assert response.body() != null;
|
||||
bodyString = response.body().string();
|
||||
} catch (Exception e) {
|
||||
throw new BusinessException(e.getMessage());
|
||||
}
|
||||
JSONObject jsonObject = JSONObject.parseObject(bodyString);
|
||||
boolean success = (boolean) jsonObject.get("success");
|
||||
if (success){
|
||||
return bodyString;
|
||||
} else {
|
||||
String message = jsonObject.get("error_code").toString() + ":" + jsonObject.get("error");
|
||||
log.error("Alipay return message : {}", message);
|
||||
throw new BusinessException("Alipay return message : " + message);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
75
src/main/java/com/ai/da/common/utils/AsyncCallerUtil.java
Normal file
75
src/main/java/com/ai/da/common/utils/AsyncCallerUtil.java
Normal file
@@ -0,0 +1,75 @@
|
||||
package com.ai.da.common.utils;
|
||||
|
||||
import com.ai.da.common.config.exception.BusinessException;
|
||||
import com.ai.da.model.dto.GenerateToPythonDTO;
|
||||
import com.ai.da.python.PythonService;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import java.util.*;
|
||||
import java.util.concurrent.*;
|
||||
|
||||
@Slf4j
|
||||
@Component
|
||||
public class AsyncCallerUtil {
|
||||
|
||||
// 存放状态 表示当前任务是否需要继续等待,默认持续等待
|
||||
public static Map<String, Boolean> waitingStatus = new HashMap<>();
|
||||
|
||||
private static PythonService pythonService;
|
||||
|
||||
@Autowired
|
||||
public void setPythonService(PythonService pythonService) {
|
||||
AsyncCallerUtil.pythonService = pythonService;
|
||||
}
|
||||
|
||||
public CompletableFuture<List<String>> callGenerateAsync(GenerateToPythonDTO generateToPython) {
|
||||
// return CompletableFuture.supplyAsync(() -> pythonService.generateSketchOrPrint(generateToPython));
|
||||
return null;
|
||||
}
|
||||
|
||||
public List<String> generate(GenerateToPythonDTO generateToPython) {
|
||||
ScheduledExecutorService scheduledExecutorService = Executors.newScheduledThreadPool(5);
|
||||
String taskId = generateToPython.getTasks_id();
|
||||
ScheduledFuture<?> timeoutTask = null;
|
||||
if (!waitingStatus.containsKey(taskId)) waitingStatus.put(taskId, true);
|
||||
|
||||
try {
|
||||
CompletableFuture<List<String>> generateResult = callGenerateAsync(generateToPython);
|
||||
// 5秒后第一次确认,之后每隔10秒确认一次用户选择结果
|
||||
timeoutTask = scheduledExecutorService.scheduleAtFixedRate(() -> {
|
||||
// 调用另一个接口获取用户的选择
|
||||
if (!waitingStatus.get(taskId)) {
|
||||
// 如果用户选择取消,则取消对generate的调用
|
||||
generateResult.cancel(true);
|
||||
waitingStatus.remove(taskId);
|
||||
} else log.info("===============持续等待===============");
|
||||
}, 5, 10, TimeUnit.SECONDS);
|
||||
|
||||
log.info("阻塞等待结果...");
|
||||
// 阻塞,等待结果
|
||||
List<String> result = generateResult.get();
|
||||
// 取消定时任务
|
||||
timeoutTask.cancel(true);
|
||||
waitingStatus.remove(taskId);
|
||||
return result;
|
||||
} catch (CancellationException e) {
|
||||
// generateResult.cancel(true);通过抛出异常取消该任务
|
||||
log.info("==========成功取消generate任务==========");
|
||||
return null;
|
||||
} catch (InterruptedException | ExecutionException | BusinessException e) {
|
||||
// 处理异常
|
||||
log.error("发生错误 : " + e, e);
|
||||
// 取消定时任务
|
||||
assert timeoutTask != null;
|
||||
timeoutTask.cancel(true);
|
||||
throw new BusinessException(e.getMessage());
|
||||
} finally {
|
||||
// 关闭线程池
|
||||
// executorService.shutdown();
|
||||
// scheduledExecutorService.shutdown();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user