ניתוח פרמטרים של שורת פקודה עם JCommander

1. סקירה כללית

במדריך זה, נלמד כיצד להשתמש ב- JCommander לניתוח פרמטרים בשורת הפקודה. נחקור כמה מהתכונות שלו כשאנחנו בונים יישום פשוט של שורת פקודה.

2. מדוע JCommander?

"מכיוון שהחיים קצרים מכדי לנתח פרמטרים בשורת הפקודה" סדריק בוסט

JCommander, שנוצר על ידי סדריק בוסט, הוא ספרייה מבוססת ביאורים עבורניתוח פרמטרים של שורת פקודה. זה יכול להפחית את המאמץ בבניית יישומי שורת פקודה ולעזור לנו לספק חווית משתמש טובה עבורם.

עם JCommander, אנו יכולים להוריד משימות מסובכות כגון ניתוח, אימות והקלדה של המרות, כדי לאפשר לנו להתמקד בלוגיקת היישום שלנו.

3. הגדרת JCommander

3.1. תצורת Maven

נתחיל בהוספת ה- jcommander תלות שלנו pom.xml:

 com.beust jcommander 1.78 

3.2. שלום עולם

בואו ניצור פשוט HelloWorldApp שלוקח קלט יחיד שנקרא שֵׁם ומדפיס ברכה, "שלום ".

מאז JCommander קושר ארגומנטים בשורת הפקודה לשדות במחלקה Javaנגדיר תחילה א HelloWorldArgs כיתה עם שדה שֵׁם ביאור עם @פָּרָמֶטֶר:

מחלקה HelloWorldArgs {@Parameter (names = "--name", תיאור = "שם משתמש", חובה = true) שם מחרוזת פרטי; }

עכשיו, בואו נשתמש ב- JCommander בכיתה לנתח את הטיעונים בשורת הפקודה ולהקצות את השדות שלנו HelloWorldArgs לְהִתְנַגֵד:

HelloWorldArgs jArgs = HelloWorldArgs חדש (); JCommander helloCmd = JCommander.newBuilder () .addObject (jArgs) .build (); helloCmd.parse (טענות); System.out.println ("שלום" + jArgs.getName ());

לבסוף, בואו נפעיל את המעמד הראשי עם אותם טיעונים מהקונסולה:

$ java HelloWorldApp - שם JavaWorld שלום JavaWorld

4. בניית יישום אמיתי ב- JCommander

כעת, לאחר שהפעלנו, בואו ניקח בחשבון מקרה שימוש מורכב יותר - לקוח API של שורת פקודה אשר מתקשר עם יישום חיוב כגון Stripe, במיוחד תרחיש חיוב מדוד (או מבוסס שימוש). שירות חיוב של צד שלישי זה מנהל את המנויים והחשבונית שלנו.

בואו נדמיין שאנחנו מנהלים עסק SaaS, בו הלקוחות שלנו קונים מנויים לשירותים שלנו ומחויבים בגין מספר שיחות ה- API לשירותים שלנו בחודש. נבצע שתי פעולות אצל הלקוח שלנו:

  • שלח: הגש כמות ומחיר שימוש ליחיד עבור לקוח כנגד מנוי נתון
  • לְהָבִיא: אחזר חיובים עבור לקוח בהתבסס על הצריכה בחלק מהמנויים שלהם או בכל החודש הנוכחי - אנו יכולים לקבל חיובים אלה מצטברים על פני כל המינויים או לפרט לפי כל מנוי.

אנו נבנה את לקוח ה- API ככל שנעבור על תכונות הספרייה.

בואו נתחיל!

5. הגדרת פרמטר

נתחיל בהגדרת הפרמטרים שבהם היישום שלנו יכול להשתמש.

5.1. ה @פָּרָמֶטֶר ביאור

הערת שדה עם @פָּרָמֶטֶר אומר ל- JCommander לקשור אליו טיעון תואם של שורת פקודה. @פָּרָמֶטֶר בעל תכונות לתיאור הפרמטר העיקרי, כגון:

  • שמות - שם אחד או יותר של האופציה, למשל "–שם" או "-n"
  • תיאור - המשמעות מאחורי האופציה, לעזור למשתמש הקצה
  • נדרש - האם האופציה היא חובה, ברירת המחדל היא שֶׁקֶר
  • arity - מספר פרמטרים נוספים שהאפשרות צורכת

בואו להגדיר פרמטר מספר לקוח בתרחיש החיוב המדוד שלנו:

@Parameter (names = {"--customer", "-C"}, תיאור = "מזהה הלקוח המשתמש בשירותים", arity = 1, חובה = true) מחרוזת customerId; 

כעת, בוא נבצע את הפקודה שלנו באמצעות הפרמטר החדש "–קונה":

אפליקציית java $ - לקוח cust0000001A קרא את CustomerId: cust0000001A. 

כמו כן, אנו יכולים להשתמש בפרמטר הקצר "-C" כדי להשיג את אותו האפקט:

$ java App -C cust0000001A קרא את CustomerId: cust0000001A. 

5.2. פרמטרים נדרשים

כאשר פרמטר הוא חובה, היישום יוצא לזרוק א ParameterException אם המשתמש לא מציין זאת:

חריג אפליקציה $ java בשרשור "ראשי" com.beust.jcommander.ParameterException: נדרשת האפשרות הבאה: [--customer | -C]

עלינו לציין כי באופן כללי, כל שגיאה בניתוח הפרמטרים גורמת ל- a ParameterException ב- JCommander.

6. סוגי מובנים

6.1. IStringConverter מִמְשָׁק

JCommander מבצע המרת סוג משורת הפקודה חוּט קלט לסוגי Java בכיתות הפרמטרים שלנו. ה IStringConverter ממשק מטפל בהמרת סוג של פרמטר מ חוּט לכל סוג שרירותי. אז כל הממירים המובנים של JCommander מיישמים את הממשק הזה.

מחוץ לקופסה, JCommander מגיע עם תמיכה בסוגי נתונים נפוצים כגון חוּט, מספר שלם, בוליאני, BigDecimal, ו Enum.

6.2. סוגי ארטי יחיד

Arity מתייחס למספר הפרמטרים הנוספים שאופציה צורכת. של JCommander סוגי פרמטרים מובנים הם בעלי ברירת מחדל של אחד, למעט בוליאני ו רשימה. לכן, סוגים נפוצים כגון חוּט, מספר שלם, BigDecimal, ארוך, ו Enum, הם סוגים חד-טבעיים.

6.3. בוליאני סוּג

שדות סוג בוליאני אוֹ בוליאני לא צריך שום פרמטר נוסף - לאפשרויות אלה יש arity של אפס.

בואו נסתכל על דוגמא. אולי אנחנו רוצים להשיג את החיובים עבור לקוח, לפי מינויים. אנחנו יכולים להוסיף a בוליאני שדה מְפוֹרָט, שזה שֶׁקֶר כברירת מחדל:

@Parameter (names = {"--itemized"}) פרט בוליאני פרטי; 

היישום שלנו יחזיר חיובים מצטברים עם מְפוֹרָט מכוון ל שֶׁקֶר. כאשר אנו קוראים לשורת הפקודה עם ה- מְפוֹרָט פרמטר, הגדרנו את השדה ל- נָכוֹן:

אפליקציית $ java - פריט הדגל קרא פריט: נכון. 

זה עובד טוב אלא אם כן יש לנו מקרה שימוש שבו אנחנו תמיד רוצים חיובים מפורטים, אלא אם כן צוין אחרת. נוכל לשנות את הפרמטר שיהיה לא פריט, אבל אולי יהיה ברור יותר להיות מסוגל לספק שֶׁקֶר כערך של מְפוֹרָט.

בואו ונציג התנהגות זו באמצעות ערך ברירת מחדל נָכוֹן עבור השדה, וקביעת שלו arity כאחד:

@Parameter (names = {"--itemized"}, arity = 1) פרטי בוליאני פרטי = true; 

כעת, כאשר אנו מציינים את האפשרות, הערך יוגדר ל- שֶׁקֶר:

אפליקציית $ java - פריט שקר קרא דגל ממוין: שקר. 

7. רשימה סוגים

JCommander מספק כמה דרכים לוויכוחים מחייבים ל רשימה שדות.

7.1. ציון הפרמטרים מרובים

נניח שאנחנו רוצים להשיג חיובים של קבוצת משנה בלבד של מנויי הלקוח:

@Parameter (names = {"- מנוי", "-S"}) מנוי רשימות פרטיות; 

השדה אינו חובה, והיישום יביא את החיובים בכל המנויים אם הפרמטר לא סופק. עם זאת, אנו יכולים לציין מספר מנויים באמצעות שם הפרמטר מספר רב של פעמים:

$ java App - S מנוי 001 - מנוי S 002 - מנוי S 003 קרא מנויים: [מנוי A001, מנוי A002, מנוי A003]. 

7.2. כריכה רשימות באמצעות המפצל

במקום לציין את האפשרות מספר פעמים, בואו ננסה לאגד את הרשימה על ידי העברת פסיק מופרד חוּט:

$ java App -S מנוי A001, מנוי A002, מנוי A003 מנויים לקריאה: [מנוי A001, מנוי A002, מנוי A003]. 

זה משתמש בערך פרמטר יחיד (arity = 1) כדי לייצג רשימה. JCommander ישתמש בכיתה CommaParameterSplitter לאגד את הפרודים בפסיקים חוּט שלנו רשימה.

7.3. כריכה רשימות באמצעות ספליטר מותאם אישית

אנו יכולים לעקוף את מפצל ברירת המחדל על ידי יישום ה- IParameterSplitter מִמְשָׁק:

מחלקה ColonParameterSplitter מיישמת IParameterSplitter {@Override פיצול רשימה רשימת (מחרוזת ערך) {להחזיר asList (value.split (":")); }}

ואז ממפה את היישום ל- מפצל תכונה ב @פָּרָמֶטֶר:

@Parameter (names = {"- מנוי", "-S"}, ספליטר = ColonParameterSplitter.class) מנוי רשימות פרטיות; 

בואו ננסה את זה:

$ java App -S "מנוי A001: מנוי A002: מנוי A003" מנויים לקריאה: [מנוי A001, מנוי A002, מנוי A003]. 

7.4. אריטיות משתנה רשימות

Arity משתנה מאפשר לנו להכריזרשימות שיכולות לקחת פרמטרים בלתי מוגדרים, עד לאפשרות הבאה. אנחנו יכולים להגדיר את התכונה משתנה כפי ש נָכוֹן כדי לציין התנהגות זו.

בואו ננסה זאת לנתח מנויים:

@Parameter (names = {"- מנוי", "-S"}, variableArity = true) מנוי רשימות פרטי; 

וכאשר אנו מריצים את הפקודה שלנו:

$ java App -S מנוי A001 מנוי 002 מנוי A003 - מנויי קריאה מזוהים: [מנוי A001, מנוי A002, מנוי A003]. 

JCommander קושר את כל טיעוני הקלט בעקבות האפשרות "-S" לשדה הרשימה, עד לאפשרות הבאה או לסוף הפקודה.

7.5. ארטיות קבועה רשימות

עד כה ראינו רשימות בלתי מוגבלות, שבהן נוכל להעביר כמה פריטי רשימה שנרצה. לפעמים, נרצה להגביל את מספר הפריטים שהועברו ל- a רשימה שדה. לשם כך אנו יכולים ציין ערך arity שלם עבור a רשימה שדהכדי להגביל את זה:

@Parameter (names = {"- מנוי", "-S"}, arity = 2) מנוי רשימות פרטי; 

Arity קבוע מכריח לבדוק את מספר הפרמטרים שהועברו ל- a רשימה אפשרות וזורק א ParameterException במקרה של הפרה:

$ java App - מנוי S 001 מנוי 002 מנוי 003 הועבר הפרמטר הראשי 'מנוי A003' אך לא הוגדר פרמטר ראשי בכיתת arg שלך 

מהודעת השגיאה עולה כי מכיוון ש- JCommander ציפה לשני טיעונים בלבד, היא ניסתה לנתח את פרמטר הקלט הנוסף "מנוי A003" כאפשרות הבאה.

8. סוגים מותאמים אישית

אנו יכולים גם לאגד פרמטרים על ידי כתיבת ממירים מותאמים אישית. כמו ממירים מובנים, ממירים מותאמים אישית חייבים ליישם את IStringConverter מִמְשָׁק.

בואו כתוב ממיר לניתוח חותמת זמן ISO8601:

class ISO8601TimestampConverter מיישם IStringConverter {פרטית סטטית סופית DateTimeFormatter TS_FORMATTER = DateTimeFormatter.ofPattern ("uuuu-MM-dd'T'HH: mm: ss"); @ עקוף המרה מיידית ציבורית (ערך מחרוזת) {נסה {להחזיר LocalDateTime .parse (ערך, TS_FORMATTER) .atOffset (ZoneOffset.UTC) .toInstant (); } לתפוס (DateTimeParseException e) {לזרוק ParameterException חדש ("חותמת זמן לא חוקית"); }}} 

קוד זה ינתח את הקלט חוּט ולהחזיר רֶגַע, זורק א ParameterException אם יש שגיאת המרה. אנו יכולים להשתמש בממיר זה על ידי קשירתו לשדה מסוג רֶגַע משתמש ב מֵמִיר תכונה ב @פָּרָמֶטֶר:

@Parameter (names = {"- timestamp"}, ממיר = ISO8601TimestampConverter.class) חותמת זמן מיידית פרטית; 

בואו נראה את זה בפעולה:

אפליקציית java $ - חותמת זמן 2019-10-03T10: 58: 00 קרא חותמת זמן: 2019-10-03T10: 58: 00Z.

9. אימות פרמטרים

JCommander מספק מספר אימות ברירת מחדל:

  • האם מסופקים פרמטרים נדרשים
  • אם מספר הפרמטרים שצוינו תואם את שטח השדה
  • בין אם כל אחד מהם חוּט ניתן להמיר את הפרמטר לסוג השדה המתאים

בנוסף, ייתכן שנרצה להוסיף אימות מותאם אישית. לדוגמא, נניח שמזהי הלקוחות חייבים להיות UUID.

אנו יכולים לכתוב מאמת לשדה הלקוח המיישם את הממשק IParameterValidator:

מחלקת UUIDValidator מיישמת IParameterValidator {פרטית סופית מחרוזת UUID_REGEX = "[0-9a-fA-F] {8} (- [0-9a-fA-F] {4}) {3} - [0-9a-fA- ו] {12} "; @Override Public void validate (שם מחרוזת, ערך מחרוזת) זורק ParameterException {if (! IsValidUUID (value)) {throw new ParameterException ("פרמטר מחרוזת" + value + "אינו UUID חוקי."); }} בוליאני פרטי isValidUUID (ערך מחרוזת) {return Pattern.compile (UUID_REGEX) .matcher (value) .matches (); }} 

ואז נוכל להתחבר עם ה- validateWith תכונה של הפרמטר:

@Parameter (names = {"--customer", "-C"}, validateWith = UUIDValidator.class) customerInd מחרוזת פרטית; 

אם נפעיל את הפקודה עם מספר לקוח שאינו UUID, היישום ייצא עם הודעת כשל באימות:

יישום $ java - C customer001 פרמטר מחרוזת customer001 אינו UUID חוקי. 

10. פקודות משנה

כעת, לאחר שלמדנו על קשירת פרמטרים, בואו נרכיב הכל כדי לבנות את הפקודות שלנו.

ב- JCommander אנו יכולים לתמוך בפקודות מרובות, הנקראות תת-פקודות, שלכל אחת מהן אפשרויות מובחנות.

10.1. @פרמטרים ביאור

אנחנו יכולים להשתמש @פרמטרים להגדרת פקודות משנה. @פרמטרים מכיל את התכונה פקודות שמות לזהות פקודה.

בואו לדגמן שלח ו לְהָבִיא כפקודות משנה:

@Parameters (commandNames = {"submit"}, commandDescription = "הגש שימוש עבור לקוח מסוים ומנוי," + "מקבל פריט שימוש אחד") class SubmitUsageCommand {// ...} @Parameters (commandNames = {"fetch" }, commandDescription = "אחזר חיובים עבור לקוח בחודש הנוכחי," + "ניתן לפרט או לצבור") class FetchCurrentChargesCommand {// ...} 

JCommander משתמש בתכונות ב- @פרמטרים להגדרת התצורה של תתי הפקודות, כגון:

  • פקודות שמות - שם פקודת המשנה; מחייב את הארגומנטים של שורת הפקודה למחלקה שמסומנת עליהם @פרמטרים
  • commandDescription - מתעד את מטרת פקודת המשנה

10.2. הוספת תת פקודות ל JCommander

אנו מוסיפים את פקודות המשנה ל JCommander עם ה addCommand שיטה:

SubmitUsageCommand submitUsageCmd = SubmitUsageCommand חדש (); FetchCurrentChargesCommand fetchChargesCmd = FetchCurrentChargesCommand חדש (); JCommander jc = JCommander.newBuilder () .addCommand (submitUsageCmd) .addCommand (fetchChargesCmd) .build (); 

ה addCommand השיטה רושמת את פקודות המשנה עם שמותיהן בהתאמה כמפורט ב commandNames תכונה של @פרמטרים ביאור.

10.3. ניתוח פקודות משנה

כדי לגשת לבחירת הפקודה של המשתמש, עלינו לנתח את הטיעונים:

jc.parse (טענות); 

לאחר מכן נוכל לחלץ את פקודת המשנה באמצעות getParsedCommand:

מחרוזת parsedCmdStr = jc.getParsedCommand (); 

בנוסף לזיהוי הפקודה, JCommander קושר את שאר הפרמטרים של שורת הפקודה לשדות שלהם בתת-הפקודה. כעת, עלינו רק להתקשר לפקודה בה אנו רוצים להשתמש:

switch (parsedCmdStr) {case "submit": submitUsageCmd.submit (); לשבור; מקרה "אחזור": fetchChargesCmd.fetch (); לשבור; ברירת מחדל: System.err.println ("פקודה לא חוקית:" + parsedCmdStr); } 

11. עזרה לשימוש ב- JCommander

אנחנו יכולים להפעיל נוֹהָג כדי להדריך מדריך שימוש. זהו סיכום של כל האפשרויות שהאפליקציה שלנו צורכת. ביישום שלנו, אנו יכולים להפעיל את השימוש בפקודה הראשית, או לחלופין, בכל אחת משתי הפקודות "להגיש" ו"להביא "בנפרד.

תצוגת שימוש יכולה לעזור לנו בכמה דרכים: הצגת אפשרויות עזרה ובמהלך טיפול בשגיאות.

11.1. מציג אפשרויות עזרה

אנו יכולים לאגד אפשרות עזרה בפקודות שלנו באמצעות בוליאני פרמטר יחד עם התכונה עֶזרָה מכוון ל נָכוֹן:

@Parameter (names = "--help", help = true) עזרה בוליאנית פרטית; 

לאחר מכן אנו יכולים לזהות אם הועבר "–עזרה" בטיעונים, ולהתקשר נוֹהָג:

אם (cmd.help) {jc.usage (); } 

בואו נראה את פלט העזרה לפקודת המשנה "שלח":

$ java הגשת אפליקציה - עזרה שימוש: הגש [אפשרויות] אפשרויות: * - לקוח, -זהה של הלקוח המשתמש בשירותים * - מנוי, -זהה של המנוי שנרכש * - כמות כמות משומשת ; הכמות המדווחת מתווספת לאורך תקופת החיוב * - סוג מחירים, -P סוג התמחור של השימוש המדווח (ערכים: [PRE_RATED, UNRATED]) * - חותמת זמן של אירוע השימוש, חייבת להיות בתקופת החיוב הנוכחית - -מחיר אם PRE_RATED, מחיר יחידה להחיל ליחידת כמות שימוש מדווחת 

ה נוֹהָג השיטה משתמשת ב @פָּרָמֶטֶר תכונות כגון תיאור כדי להציג סיכום מועיל. פרמטרים המסומנים בכוכבית (*) הם חובה.

11.2. טיפול בשגיאות

אנחנו יכולים לתפוס את ParameterException ולהתקשר נוֹהָג כדי לעזור למשתמש להבין מדוע הקלט שלהם לא היה נכון. ParameterException מכיל את JCommander מופע כדי להציג את העזרה:

נסה {jc.parse (טענות); } לתפוס (ParameterException e) {System.err.println (e.getLocalizedMessage ()); jc.usage (); } 

12. סיכום

במדריך זה השתמשנו ב- JCommander לבניית יישום שורת פקודה. אמנם סיקרנו רבות מהתכונות העיקריות, אך יש עוד בתיעוד הרשמי.

כרגיל, קוד המקור של כל הדוגמאות זמין ב- GitHub.


$config[zx-auto] not found$config[zx-overlay] not found