1,下载源码:Astrolog Website
https://www.astrolog.org/astrolog.htm ---->Download files --->Astrolog 7.60 source code
2,上传服务器,解压,然后到源文件目录执行make(输入make命令)
遇见问题:
1)ImportError: libX11.so.6: cannot open shared object file: No such file or directory
执行yum命令:
sudo yum install libX11
sudo yum install libXext
2)Centos编译软件提示:X11/Xlib.h:没有那个文件或目录
执行yum命令:
sudo yum install libX*
编译成功后,你会得到一个astrolog执行文件
先试试水,执行命令,OK说明编译成功了:
./astrolog -qa 3 11 1993 10:10 -8 -116.40 39.90 -R0[ 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 22 25 28 31 34] -v -A3 -c 2
参数含义:
-qa 月 日 年 时间
-8 东八区
-116.40 东经116.40度 也可以116:24E
39.9 南纬39.9
-RO 需要显示的行星,这里是ID,可以用命令 ./astrolog -R1 -HO 查询所有支持的行星
-v 显示对象位置列表 (默认情况下选择)
-A3 回归黄道(好像是这么个意思)
-c 2 盘面宫位使用等宫制
具体使用参数可以看 astrolog.htm 文件,下载一个Windows版本,安装完在安装文件下
3,API接口制作
这里使用java ProcessBuilder进行调用,主要难度在于读懂astrolog的入参,建议打开Windows版本,结合astrolog.htm文件一起。
主要解析代码:
import java.io.*; import java.nio.charset.StandardCharsets; import java.util.List; import java.util.Map; import java.util.concurrent.TimeUnit; import java.util.regex.Matcher; import java.util.regex.Pattern; import java.util.stream.Collectors; import org.jetbrains.annotations.NotNull; import com.cdslinks.astro.div.astrlog.domain.*; import com.cdslinks.astro.div.astrlog.rsp.AstroDrawV2Rsp; import com.google.common.collect.ImmutableMap; import com.google.common.collect.Lists; import cn.hutool.core.collection.CollUtil; import cn.hutool.core.date.DatePattern; import cn.hutool.core.date.DateTime; import cn.hutool.core.date.DateUtil; import cn.hutool.core.io.FileUtil; import cn.hutool.core.util.StrUtil; import lombok.extern.slf4j.Slf4j; import vip.xiaonuo.common.exception.CommonException; /** * * @author xpw * @version JDK 8 * @className CommandUtils * @date 2024/3/5 16:01 * @description 执行结果处理工具 */ @Slf4j public class CommandUtils { // 字符分割常量 private static final String SPLITE_STR = "$#$"; // 宫位提取正则 private static final Pattern HOUSE_PATTERN = Pattern.compile("House cusp.*");; // 宫位落星座提取正则 private static final Pattern HOUSE_SIGN_PATTERN = Pattern.compile("[a-zA-Z]+|\\d+");; // 宫位数据 private static final Map<String, String> HOUSE_MAP = new ImmutableMap.Builder<String, String>().put("1", "命宫").put("2", "财帛宫").put("3", "兄弟宫") .put("4", "田宅宫").put("5", "子女宫").put("6", "奴仆宫").put("7", "夫妻宫").put("8", "疾厄宫").put("9", "迁移宫") .put("10", "官禄宫").put("11", "福德宫").put("12", "玄秘宫").build(); // 星座数据 private static final Map<String, String> SIGN_MAP = new ImmutableMap.Builder<String, String>().put("1", "Aries").put("2", "Taurus").put("3", "Gemini") .put("4", "Cancer").put("5", "Leo").put("6", "Virgo").put("7", "Libra").put("8", "Scorpio") .put("9", "Sagittarius").put("10", "Capricorn").put("11", "Aquarius").put("12", "Pisces").build(); private static final Map<String, String> SIGN_SIMP_MAP = new ImmutableMap.Builder<String, String>().put("Ari", "1").put("Tau", "2") .put("Gem", "3").put("Can", "4").put("Leo", "5").put("Vir", "6").put("Lib", "7").put("Sco", "8") .put("Sag", "9").put("Cap", "10").put("Aqu", "11").put("Pis", "12").build(); private static final Map<String, String> SIGN_NAME_MAP = new ImmutableMap.Builder<String, String>().put("1", "白羊座").put("2", "金牛座") .put("3", "双子座").put("4", "巨蟹座").put("5", "狮子座").put("6", "处女座").put("7", "天秤座").put("8", "天蝎座") .put("9", "射手座").put("10", "摩羯座").put("11", "水瓶座").put("12", "双鱼座").build(); // 星体数据 private static final Map<String, String> PLANET_MAP = new ImmutableMap.Builder<String, String>().put("Sun", "1").put("Moon", "2") .put("Mercury", "3").put("Venus", "4").put("Mars", "5").put("Jupiter", "6").put("Saturn", "7") .put("Uranus", "8").put("Neptune", "9").put("Pluto", "10").put("Chiron", "11").put("Ceres", "12") .put("Pallas", "13").put("Juno", "14").put("Vesta", "15").put("North Node", "16").put("South Node", "17") .put("Lilith", "18").put("Fortune", "19").put("Vertex", "20").put("East Point", "21").put("Ascendant", "22") .put("Nadir", "25").put("Descendant", "28").put("Midheaven", "31").build(); private static final Map<String, String> PLANET_ID_MAP = new ImmutableMap.Builder<String, String>().put("1", "太阳").put("2", "月亮").put("3", "水星") .put("4", "金星").put("5", "火星").put("6", "木星").put("7", "土星").put("8", "天王").put("9", "海王星").put("10", "冥王星") .put("11", "凯龙").put("12", "谷神").put("13", "智神").put("14", "婚神").put("15", "灶神").put("16", "北交") .put("17", "南交").put("18", "莉莉丝").put("19", "福点").put("20", "宿命").put("21", "东升").put("22", "ASC") .put("25", "IC").put("28", "DSC").put("31", "MC").build(); private static final Map<String, String> PLANET_NAME_MAP = new ImmutableMap.Builder<String, String>().put("1", "Sun").put("2", "Moon") .put("3", "Mercury").put("4", "Venus").put("5", "Mars").put("6", "Jupiter").put("7", "Saturn") .put("8", "Uranus").put("9", "Neptune").put("10", "Pluto").put("11", "Chiron").put("12", "Ceres") .put("13", "Pallas").put("14", "Juno").put("15", "Vesta").put("16", "meanNode").put("17", "meanSouthNode") .put("18", "meanApogee").put("19", "PartOfFortune").put("22", "Ascendant").put("25", "IC").put("28", "Des") .put("31", "MC").build(); // 容许度 private static final Map<String, String> ASPECT_MAP = new ImmutableMap.Builder<String, String>().put("Con", "0") .put("Opp", "180").put("Squ", "90").put("Tri", "120").put("Sex", "60").put("Inc", "150").put("SSx", "30") .put("SSq", "45").put("Ses", "135").put("Qui", "72").put("BQn", "144").put("SQn", "36").put("Sep", "51.43") .put("Nov", "40").put("BNv", "80").put("BSp", "102.86").put("TSp", "154.29").put("QNv", "160").put("TDc", "108") .put("Un1", "32.73").put("Un2", "65.45").put("Un3", "98.18").put("Un4", "130.91").put("Un5", "163.64").build(); private static final Map<String, String> ASPECT_NAME_MAP = new ImmutableMap.Builder<String, String>().put("Con", "合相").put("Opp", "冲相") .put("Squ", "刑相").put("Tri", "拱相").put("Sex", "六合相").put("Inc", "梅花相").put("SSx", "十二分相").put("SSq", "八分相") .put("Ses", "补八分相").put("Qui", "五分相").put("BQn", "补五分相").put("SQn", "十分相").build(); // 星盘查询 public static AstroDrawV2Rsp queryAstrInfo(String astrlogPath, AstrlogV2QueryParam astrlogQueryParam) { // 获取公共参数 List<String> commonCommand = getCommonCommand(astrlogPath, astrlogQueryParam); // 先查星盘基本信息 // $#$Astrolog 7.60 chart for Thu Mar 11, 1993 10:10am (ST Zone 8E) 116:24E 39:54N$#$Body Locat. Ret. Lati. Rul. // House Rul. Veloc. Equal Houses$#$$#$Sun : 20Pis31 - 0:00' (-) [10th house] [-] +0.998 - House cusp 1: // 8Gem53$#$Moon: 28Lib28 - 3:43' (-) [ 5th house] [-] +14.70 - House cusp 2: 8Can53$#$Merc: 16Pis41 R + 3:24' // (d) [10th house] [-] -0.984 - House cusp 3: 8Leo53$#$Venu: 20Ari01 + 7:02' (d) [11th house] [-] +0.012 - // House cusp 4: 8Vir53$#$Mars: 11Can47 + 3:01' (f) [ 2nd house] [d] +0.243 - House cusp 5: 8Lib53$#$Jupi: // 12Lib11 R + 1:34' (-) [ 5th house] [-] -0.111 - House cusp 6: 8Sco53$#$Satu: 24Aqu23 - 1:04' (R) [ 9th house] // [-] +0.112 - House cusp 7: 8Sag53$#$Uran: 21Cap18 - 0:25' (-) [ 8th house] [X] +0.036 - House cusp 8: // 8Cap53$#$Nept: 20Cap39 + 0:40' (f) [ 8th house] [-] +0.022 - House cusp 9: 8Aqu53$#$Plut: 25Sco28 R +14:38' // (R) [ 6th house] [-] -0.007 - House cusp 10: 8Pis53$#$Chir: 18Leo19 R - 7:03' (-) [ 3rd house] [-] -0.058 - // House cusp 11: 8Ari53$#$Cere: 17Pis01 - 7:55' (-) [10th house] [f] +0.393 - House cusp 12: 8Tau53$#$Pall: // 19Aqu40 +20:35' (-) [ 9th house] [-] +0.324$#$Juno: 5Can41 -12:32' (-) [ 1st house] [d] +0.240 Car Fix Mut // TOT +:13$#$Vest: 3Aqu16 + 0:01' (X) [ 8th house] [R] +0.486 Fir 1 2 2 5 -:11$#$Nort: 16Sag46 R + 0:00' (f) [ // 7th house] [-] -0.052 Ear 3 0 0 3 M:13$#$Sout: 16Gem46 R + 0:00' (f) [ 1st house] [-] -0.052 Air 2 4 2 8 N: // 7$#$Lili: 16Pis14 + 5:08' (X) [10th house] [-] +0.112 Wat 2 1 5 8 A:10$#$Fort: 16Cap50 + 0:00' (-) [ 8th // house] [-] +412.4 TOT 8 7 9 24 D:10$#$Asce: 8Gem53 + 0:00' [ 1st house] +398.7 <: 7$#$Nadi: 15Leo11 + 0:00' [ // 3rd house] +362.5$#$Desc: 8Sag53 + 0:00' [ 7th house] +398.7$#$Midh: 15Aqu11 + 0:00' [ 9th house] // +362.5$#$Vulc: 27Pis52 + 0:01' (d) [10th house] [X] +0.024 String commandResult = getCommandResult(astrlogPath, commonCommand); log.info("星盘基本信息-:{}", commandResult); // 解析基本信息 AstroDrawV2Rsp astroDrawRsp = dealBaseInfo(commandResult); // 再查允许度信息 commonCommand.addAll(getAspect()); // $#$Astrolog 7.60 chart for Thu Mar 11, 1993 10:10am (ST Zone 8E) 116:24E 39:54N$#$$#$ 1: Sun (Pis) Sex (Cap) // Neptune - orb: -0:08' - power: 10.37$#$ 2: Sun (Pis) Sex (Cap) Uranus - orb: -0:47' - power: 6.91$#$ 3: // Mercury [Pis] Squ [Sag] North Node - orb: -0:04' - power: 5.67$#$ 4: Venus (Ari) Sex (Aqu) Pallas - orb: // -0:11' - power: 3.92$#$ 5: Mercury [Pis] Sex (Cap) Fortune - orb: -0:06' - power: 3.91$#$ 6: Ceres (Pis) Squ // [Sag] North Node - orb: +0:15' - power: 3.50$#$ 7: Mars (Can) Squ [Lib] Jupiter - orb: +0:18' - power: // 3.09$#$ 8: Moon (Lib) Inc (Pis) Vulcan - orb: -0:47' - power: 2.73$#$ 9: North N [Sag] Squ (Pis) Lilith - // orb: -0:30' - power: 2.67$#$ 10: Ceres (Pis) Sex (Cap) Fortune - orb: +0:29' - power: 2.37$#$ 11: Uranus // (Cap) Con (Cap) Fortune - orb: +4:28' - power: 2.16$#$ 12: Juno (Can) Inc (Sag) Descendant - orb: +0:36' - // power: 2.09$#$ 13: Juno (Can) Inc (Aqu) Vesta - orb: -0:04' - power: 1.92$#$ 14: Lilith (Pis) Sex (Cap) // Fortune - orb: -0:27' - power: 1.85$#$ 15: South N [Gem] Inc (Cap) Fortune - orb: -0:04' - power: 1.73$#$ 16: // Venus (Ari) Squ (Cap) Uranus - orb: -1:13' - power: 1.34$#$ 17: South N [Gem] Tri (Aqu) Midheaven - orb: // +1:34' - power: 1.28$#$ 18: North N [Sag] Tri (Leo) Nadir - orb: +1:34' - power: 0.96$#$ 19: Lilith (Pis) Inc // (Leo) Nadir - orb: -1:26' - power: 0.79$#$ 20: Fortune (Cap) Inc (Leo) Nadir - orb: +1:39' - power: 0.49$#$ // 21: Vesta (Aqu) Tri (Gem) Ascendant - orb: +5:37' - power: 0.48$#$ 22: Juno (Can) Squ (Pis) Vulcan - orb: // +7:37' - power: 0.17$#$ 23: Uranus (Cap) Sex (Pis) Ceres - orb: -3:58' - power: 0.02$#$$#$Sum power: 60.41 - // Average power: 2.63$#$Con: 1 Opp: 0 Squ: 6 Tri: 3 Sex: 7 Inc: 6$#$Sun: 2 Moo: 1 Mer: 2 Ven: 2 Mar: 1 Jup: 1 // Sat: 0 Ura: 4$#$Nep: 1 Plu: 0 Chi: 0 Cer: 3 Pal: 1 Jun: 3 Ves: 2 Nor: 4$#$Sou: 2 Lil: 3 For: 6 Asc: 1 Nad: 3 // Des: 1 Mid: 1 Vul: 2 String commandAspectResult = getCommandResult(astrlogPath, commonCommand); log.info("星盘容许度信息-:{}", commandAspectResult); // 解析允许度信息 List<PlanetAllowDegreeBean> planetAllowDegreeBeans = dealAspectInfo(commandAspectResult); astroDrawRsp.setPlanetAllows(planetAllowDegreeBeans); return astroDrawRsp; } // 获取公共执行参数 private static List<String> getCommonCommand(String astrlogPath,AstrlogV2QueryParam astrlogQueryParam) { List<String> commands = Lists.newArrayList(); commands.add(astrlogPath + "/astrolog"); // 出生日期 String birthday = astrlogQueryParam.getBirthday(); DateTime birthdayDate = DateUtil.parse(birthday, DatePattern.NORM_DATETIME_PATTERN); // 出生时间 commands.add("-qa"); commands.add(DateUtil.format(birthdayDate, "M")); commands.add(DateUtil.format(birthdayDate, "d")); commands.add(DateUtil.format(birthdayDate, "yyyy")); commands.add(DateUtil.format(birthdayDate, "HH:mm")); // 夏令时 if (StrUtil.equals("DAYLIGHT_SAVING_TIME", astrlogQueryParam.getDst())) { commands.add("-z0"); commands.add("y"); } // 时区 commands.add("-8"); // 经度 commands.add("-" + astrlogQueryParam.getLongitude()); // 纬度 commands.add(astrlogQueryParam.getLatitude()); // 星体 commands.add("-R0[ " + CollUtil.join(astrlogQueryParam.getPlanets(), " ") + "]"); // 等宫制 commands.add("-c"); commands.add("2"); // 黄道位置计算 commands.add("-A3"); return commands; } private static String getCommandResult(String astrlogPath, List<String> commands) { File file = FileUtil.file(astrlogPath); String commandStr = CollUtil.join(commands, " "); log.info("执行命令:{}", commandStr); ProcessBuilder processBuilder = new ProcessBuilder("/bin/sh", "-c", commandStr); processBuilder.directory(file); // 将子进程标准I/O的源和目标设置为与当前Java进程的源和目标相同 processBuilder.redirectErrorStream(true); Process process = null; try { process = processBuilder.start(); // 使当前线程等待,直到子进程终止或指定的等待时间结束 // 返回值:如果子进程已退出,则为True;如果子进程退出之前超过了等待时间,则为false process.waitFor(10, TimeUnit.SECONDS); // 正常结果 try (InputStream inputStream = process.getInputStream();) { String resultStr = getResultStr(inputStream); if (StrUtil.isNotBlank(resultStr)) { return resultStr; } } // 异常结果 try (InputStream inputStream = process.getErrorStream();) { String resultStrError = getResultStr(inputStream); if (StrUtil.isNotBlank(resultStrError)) { return resultStrError; } } } catch (Exception e) { log.error("Command exe error:", e); } finally { if (process != null) { process.destroy(); } } return null; } // 获取执行结果 private static String getResultStr(InputStream inputStream) throws IOException { try (BufferedReader input = new BufferedReader(new InputStreamReader(inputStream, StandardCharsets.UTF_8));) { StringBuilder builder = StrUtil.builder(); String ss = null; while ((ss = input.readLine()) != null) { // 添加分隔符 builder.append(SPLITE_STR); builder.append(ss); } return builder.toString(); } } // 允许度参数 private static List<String> getAspect() { // -A 6 -Am 1 1 -Am 2 0.5 -Am 3 1.5 -Am 4 1.5 -Am 5 0.5 -Am 6 0.5 -Ao 1 8 -Ao 2 8 -Ao 3 8 -Ao 4 6 -Ao 5 4 -Ao 6 // 2 return Lists.newArrayList("-A", "6", "-Am", "1", "1", "-Am", "2", "0.5", "-Am", "3", "1.5", "-Am", "4", "1.5", "-Am", "5", "0.5", "-Am", "6", "0.5", "-Am", "7", "0.5", "-Am", "8", "7", "-Am", "9", "0.5", "-Am", "10", "0.5", "-Am", "11", "0.5", "-Ao", "1", "8", "-Ao", "2", "8", "-Ao", "3", "8", "-Ao", "4", "6", "-Ao", "5", "4", "-Ao", "6", "2", "-a"); } // 获取星体ID private static String getPlanetId(String queryKey) { String s = PLANET_MAP.get(queryKey); if (StrUtil.isNotBlank(s)) { return s; } List<String> collect = PLANET_MAP.keySet().stream().filter(y -> StrUtil.startWith(y, queryKey)).collect(Collectors.toList()); if (CollUtil.isEmpty(collect)) { return null; } return PLANET_MAP.get(collect.get(0)); } // 处理星盘基本信息 // 宫位和星体信息 private static AstroDrawV2Rsp dealBaseInfo(String content) { AstroDrawV2Rsp astroDrawRsp = new AstroDrawV2Rsp(); if (StrUtil.isBlank(content)) { return astroDrawRsp; } List<String> split = StrUtil.split(content, SPLITE_STR); // 不为空 List<String> collect = split.stream().filter(StrUtil::isNotBlank).collect(Collectors.toList()); if (collect.size() > 2) { // 去掉前2行 collect = collect.subList(2, collect.size()); } else { throw new CommonException("星盘查询失败!"); } // 开始处理数据 // 先匹配出宫位数据 List<HouseInfo> houseInfos = Lists.newArrayList(); collect.forEach(y -> { Matcher matcher = HOUSE_PATTERN.matcher(y); if (matcher.find()) { String matchedStr = matcher.group(); String[] houseCusps = StrUtil.replace(matchedStr, "House cusp", "").split(":"); // 宫位 String houseId = houseCusps[0].trim(); HouseInfo houseInfo = new HouseInfo(); houseInfo.setHouseId(houseId); houseInfo.setHouseLife(HOUSE_MAP.get(houseId)); // 获取星座信息 SignInfo signInfo = getSignInfo(houseCusps[1].trim()); houseInfo.setSign(signInfo); houseInfos.add(houseInfo); } }); // 再匹配星座数据 List<PlanetInfo> planetInfos = Lists.newArrayList(); collect.forEach(y -> { // 星体信息 String sub = StrUtil.sub(y, 0, 13); // 宫位ID String houseId = StrUtil.sub(y, 29, 31); // 速度 String speed = StrUtil.sub(y, 45, 51); String[] splitPlanet = sub.split(":"); String planetId = getPlanetId(splitPlanet[0].trim()); // 获取星座信息 SignInfo signInfo = getSignInfo(splitPlanet[1].trim()); PlanetInfo planetInfo = new PlanetInfo(); planetInfo.setPlanetId(planetId); planetInfo.setPlanetChinese(PLANET_ID_MAP.get(planetId)); // 为了适配原接口,修改字段内容 planetInfo.setPlanetEnglish(PLANET_NAME_MAP.get(planetId)); planetInfo.setSpeed(StrUtil.isBlank(speed) ? 0 : Double.parseDouble(speed.trim())); planetInfo.setHouseId(houseId.trim()); planetInfo.setSign(signInfo); planetInfos.add(planetInfo); }); astroDrawRsp.setHouse(houseInfos); astroDrawRsp.setPlanet(planetInfos); return astroDrawRsp; } // 处理相位信息 private static List<PlanetAllowDegreeBean> dealAspectInfo(String content) { List<PlanetAllowDegreeBean> planetAllows = Lists.newArrayList(); if (StrUtil.isBlank(content)) { return planetAllows; } List<String> split = StrUtil.split(content, SPLITE_STR); // 不为空 List<String> collect = split.stream().filter(StrUtil::isNotBlank).collect(Collectors.toList()); if (collect.size() > 1 && collect.size() > 5) { collect = collect.subList(1, collect.size() - 5); } else { throw new CommonException("星盘查询失败!"); } if (CollUtil.isEmpty(collect)) { return planetAllows; } for (String s : collect) { // 主星体信息 String planet = StrUtil.sub(s, 4, 12); // 容许度 String aspect = StrUtil.sub(s, 19, 22); // 对端星体信息 String otherPlanet = StrUtil.sub(s, 29, 40); // 度数 String allow = StrUtil.sub(s, 46, 52); PlanetAllowDegreeBean planetAllowDegreeBean = new PlanetAllowDegreeBean(); String planetId = getPlanetId(planet.trim()); planetAllowDegreeBean.setPlanetId(planetId); planetAllowDegreeBean.setPlanetChinese(PLANET_ID_MAP.get(planetId)); // 为了适配原接口,修改字段内容 planetAllowDegreeBean.setPlanetEnglish(PLANET_NAME_MAP.get(planetId)); String otherPlanetId = getPlanetId(otherPlanet.trim()); planetAllowDegreeBean.setOtherPlanetId(otherPlanetId); planetAllowDegreeBean.setOtherPlanetChinese(PLANET_ID_MAP.get(otherPlanetId)); // 为了适配原接口,修改字段内容 planetAllowDegreeBean.setOtherPlanetEnglish(PLANET_NAME_MAP.get(otherPlanetId)); // 容许度 planetAllowDegreeBean.setAspectName(ASPECT_NAME_MAP.get(aspect.trim())); planetAllowDegreeBean.setAspectCode(ASPECT_MAP.get(aspect.trim())); allow = allow.trim(); planetAllowDegreeBean.setInOut(StrUtil.startWith(allow, "+") ? 1 : -1); allow = StrUtil.sub(allow, 1, allow.length()); String[] splitAllow = allow.split(":"); planetAllowDegreeBean.setDeg(Integer.parseInt(splitAllow[0])); planetAllowDegreeBean.setMin(Integer.parseInt(splitAllow[1])); planetAllows.add(planetAllowDegreeBean); } return planetAllows; } // 获取星座信息 @NotNull private static SignInfo getSignInfo(String signStr) { // 宫位落在星座 SignInfo signInfo = new SignInfo(); // 星座 Matcher signMatcher = HOUSE_SIGN_PATTERN.matcher(signStr); List<String> signs = Lists.newArrayList(); while (signMatcher.find()) { signs.add(signMatcher.group()); } String s = signs.get(1); String signId = SIGN_SIMP_MAP.get(s); String signEnglish = SIGN_MAP.get(signId); String signChinese = SIGN_NAME_MAP.get(signId); signInfo.setSignId(signId); signInfo.setSignEnglish(signEnglish); signInfo.setSignChinese(signChinese); signInfo.setDeg(Integer.parseInt(signs.get(0))); signInfo.setMin(Integer.parseInt(signs.get(2))); return signInfo; } }