├── LICENSE ├── README.md ├── data.sql ├── pom.xml └── src └── main ├── java └── fun │ └── diviner │ └── aidiviner │ ├── Main.java │ ├── config │ ├── ExceptionConfig.java │ ├── Interceptor │ │ ├── CaptchaInterceptor.java │ │ ├── PreInterceptor.java │ │ ├── ToolInterceptor.java │ │ └── auth │ │ │ ├── AuthInterceptor.java │ │ │ └── JWTUtil.java │ ├── MyBatisConfig.java │ ├── RedisConfig.java │ ├── ScheduleConfig.java │ └── WebConfig.java │ ├── controller │ ├── CommonController.java │ ├── ToolController.java │ └── UserController.java │ ├── diviner │ ├── BaZi.java │ ├── MeiHua.java │ ├── Tarot.java │ ├── ai │ │ ├── AIModel.java │ │ ├── AIRequestUtil.java │ │ └── ReasoningResponse.java │ ├── bazi │ │ ├── BaZiMap.java │ │ ├── BaZiSetting.java │ │ ├── BaZiTool.java │ │ ├── BaZiUtil.java │ │ └── shensha │ │ │ ├── BaZiShenShaMap.java │ │ │ └── BaZiShenShaUtil.java │ ├── liuyao │ │ ├── LiuYaoMap.java │ │ ├── LiuYaoObj.java │ │ ├── LiuYaoSetting.java │ │ └── LiuYaoUtil.java │ ├── meihua │ │ ├── MeiHuaMap.java │ │ ├── MeiHuaObj.java │ │ ├── MeiHuaSetting.java │ │ └── MeiHuaUtil.java │ ├── type │ │ ├── BaZiArrangeItem.java │ │ ├── BaZiArrangeResponse.java │ │ ├── LiuYaoArrangeResponse.java │ │ ├── LiuYaoItem.java │ │ ├── MeiHuaArrangeResponse.java │ │ ├── MeiHuaGuaItem.java │ │ └── TarotResponse.java │ └── util │ │ ├── BaiduMapsUtil.java │ │ ├── CommonUtil.java │ │ └── DateUtil.java │ ├── dto │ ├── common │ │ ├── GetRecordIdParameter.java │ │ └── GetRecordParameter.java │ ├── tool │ │ ├── bazi │ │ │ ├── BaZiArrangeParameter.java │ │ │ └── BaZiSolveParameter.java │ │ ├── liuyao │ │ │ └── LiuYaoArrangeParameter.java │ │ ├── meihua │ │ │ ├── MeiHuaArrangeParameter.java │ │ │ └── MeiHuaSolveParameter.java │ │ ├── tarot │ │ │ ├── TarotCommonParameter.java │ │ │ └── TarotSelectParameter.java │ │ └── xiaoliuren │ │ │ └── XiaoLiuRenSolveParameter.java │ └── user │ │ ├── GetRechargeParameter.java │ │ ├── GetRecordParameter.java │ │ ├── ModifyAccountParameter.java │ │ ├── OpenVIPParameter.java │ │ ├── RechargeParameter.java │ │ ├── RegisterLoginParameter.java │ │ └── UseCardParameter.java │ ├── entity │ ├── Auth.java │ ├── Pay.java │ ├── PayType.java │ ├── Special.java │ ├── Trade.java │ └── database │ │ ├── Card.java │ │ ├── CardRecord.java │ │ ├── Core.java │ │ ├── Group.java │ │ ├── Recharge.java │ │ ├── Record.java │ │ ├── Tool.java │ │ ├── ToolTarotCard.java │ │ ├── ToolTarotSpread.java │ │ └── User.java │ ├── mapper │ ├── CardMapper.java │ ├── CardRecordMapper.java │ ├── CoreMapper.java │ ├── GroupMapper.java │ ├── RechargeMapper.java │ ├── RecordMapper.java │ ├── ToolMapper.java │ ├── ToolTarotCardMapper.java │ ├── ToolTarotSpreadMapper.java │ └── UserMapper.java │ ├── redis │ ├── AccessTokenRedis.java │ └── CaptchaRedis.java │ ├── service │ ├── CommonService.java │ ├── UserService.java │ ├── UtilService.java │ └── tool │ │ ├── BaZiService.java │ │ ├── MeiHuaService.java │ │ └── TarotService.java │ └── util │ ├── Auxiliary.java │ ├── response │ ├── ExceptionResponse.java │ ├── ExceptionResponseCode.java │ └── GenerateResponse.java │ └── yi_pay │ ├── YiPay.java │ ├── YiPayResponse.java │ └── YiPayType.java └── resources └── application.yml /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2025 LetFate 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ## 介绍 2 | 一个AI聊天助手,可以辅助解卦,塔罗占卜,八字命理 3 | ## 前端 4 | [AI-Diviner-Frontend](https://github.com/Let-Fate/AI-Diviner-Frontend) 5 | ## 部署 6 | 1. 请先安装Java21,MySQL8以及Redis 7 | 2. 修改`src/main/resources/application.yml`文件将数据库和Redis配置修改为自己的配置 8 | 3. 修改`src/main/java/fun/diviner/aidiviner/entity/Special.java`将里面的authSecret修改为自己的 9 | 4. 修改`src/main/java/fun/diviner/aidiviner/diviner/ai/AIModel.java`填入自己的模型密钥 10 | 5. 将根目录下的data.sql导入到数据库中 11 | 6. 修改数据库中的支付配置,往下看[支付配置](#支付配置) 12 | 7. 运行`mvn clean package`打包项目 13 | 8. 运行`java -jar target/ai-diviner-backend-1.0.0.jar`启动项目 14 | ### 支付配置 15 | 首先进入core表中,修改以下字段: 16 | 1. `yiPayId`(易支付ID) 17 | 2. `yiPayMerchantPrivateKey`(易支付商户私钥) 18 | 3. `yiPayPlatformPublicKey`(易支付平台公钥) 19 | 4. `yiPayNoticeUrlPrefix`(易支付后端回调前缀),比如说你的后端API域名是`https://api.ai.diviner.fun`,那么这个字段值就是`https://api.ai.diviner.fun`,不要带最后的`/` 20 | 5. `yiPayReturnUrl`(易支付前端回调地址),这个输入你的前端网址即可 21 | > 我这里使用的是[易支付](https://yi-pay.com/)这家的平台,你也可以使用其他的同类型的平台,通常情况下应该只需要修改`src/main/java/fun/diviner/aidiviner/util/yi_pay/YiPay.java`这个中的支付接口网址即可 -------------------------------------------------------------------------------- /pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 4.0.0 6 | 7 | 8 | org.springframework.boot 9 | spring-boot-starter-parent 10 | 3.3.2 11 | 12 | 13 | 14 | fun.diviner.aidiviner 15 | ai-diviner-backend 16 | 1.0.0 17 | 18 | 19 | UTF-8 20 | 21 21 | 22 | 3.5.7 23 | 5.8.29 24 | 0.12.6 25 | 26 | 0.13.0 27 | 1.2.58 28 | 2.6 29 | 2.6 30 | 1.6 31 | 3.8.1 32 | 1.7.2 33 | 1.3.14 34 | 35 | 36 | 37 | 38 | org.springframework.boot 39 | spring-boot-starter-actuator 40 | 41 | 42 | 43 | org.springframework.boot 44 | spring-boot-starter-web 45 | 46 | 47 | 48 | org.springframework.boot 49 | spring-boot-starter-validation 50 | 51 | 52 | 53 | org.springframework.boot 54 | spring-boot-starter-data-redis 55 | 56 | 57 | 58 | com.mysql 59 | mysql-connector-j 60 | runtime 61 | 62 | 63 | 64 | com.baomidou 65 | mybatis-plus-spring-boot3-starter 66 | ${mybatis-plus.version} 67 | 68 | 69 | 70 | org.projectlombok 71 | lombok 72 | provided 73 | 74 | 75 | 76 | cn.hutool 77 | hutool-all 78 | ${hutool.version} 79 | 80 | 81 | 82 | io.jsonwebtoken 83 | jjwt-api 84 | ${jjwt.version} 85 | 86 | 87 | 88 | io.jsonwebtoken 89 | jjwt-impl 90 | ${jjwt.version} 91 | runtime 92 | 93 | 94 | 95 | io.jsonwebtoken 96 | jjwt-jackson 97 | ${jjwt.version} 98 | runtime 99 | 100 | 101 | 102 | com.squareup.okhttp3 103 | okhttp 104 | 105 | 106 | 107 | 108 | com.openai 109 | openai-java 110 | ${openai.version} 111 | 112 | 113 | 114 | com.alibaba 115 | fastjson 116 | ${fastjson.version} 117 | 118 | 119 | 120 | commons-io 121 | commons-io 122 | ${commons-io.version} 123 | 124 | 125 | 126 | commons-lang 127 | commons-lang 128 | ${commons-lang.version} 129 | 130 | 131 | 132 | commons-validator 133 | commons-validator 134 | ${commons-validator.version} 135 | 136 | 137 | 138 | org.apache.commons 139 | commons-lang3 140 | ${commons-lang3.version} 141 | 142 | 143 | 144 | org.lionsoul 145 | ip2region 146 | ${ip2region.versoin} 147 | 148 | 149 | 150 | cn.6tail 151 | lunar 152 | ${lunar.version} 153 | 154 | 155 | 156 | 157 | 158 | 159 | org.springframework.boot 160 | spring-boot-maven-plugin 161 | 162 | 163 | 164 | 165 | -------------------------------------------------------------------------------- /src/main/java/fun/diviner/aidiviner/Main.java: -------------------------------------------------------------------------------- 1 | package fun.diviner.aidiviner; 2 | 3 | import org.springframework.boot.autoconfigure.SpringBootApplication; 4 | import org.springframework.boot.SpringApplication; 5 | 6 | @SpringBootApplication 7 | public class Main { 8 | public static void main(String[] args) { 9 | SpringApplication.run(Main.class, args); 10 | } 11 | } -------------------------------------------------------------------------------- /src/main/java/fun/diviner/aidiviner/config/ExceptionConfig.java: -------------------------------------------------------------------------------- 1 | package fun.diviner.aidiviner.config; 2 | 3 | import org.springframework.web.bind.annotation.RestControllerAdvice; 4 | import org.springframework.web.bind.annotation.ExceptionHandler; 5 | import org.springframework.web.bind.annotation.ResponseStatus; 6 | import org.springframework.web.bind.MethodArgumentNotValidException; 7 | import org.springframework.web.servlet.NoHandlerFoundException; 8 | import org.springframework.http.HttpStatus; 9 | import org.springframework.http.ResponseEntity; 10 | import org.springframework.validation.beanvalidation.SpringValidatorAdapter; 11 | 12 | import fun.diviner.aidiviner.util.response.GenerateResponse; 13 | import fun.diviner.aidiviner.util.response.ExceptionResponse; 14 | import fun.diviner.aidiviner.util.response.ExceptionResponseCode; 15 | 16 | @RestControllerAdvice 17 | public class ExceptionConfig { 18 | @ExceptionHandler(NoHandlerFoundException.class) 19 | @ResponseStatus(HttpStatus.NOT_FOUND) 20 | public GenerateResponse noHandlerFoundExceptionHandle() { 21 | return new GenerateResponse<>(404, "未找到页面"); 22 | } 23 | 24 | @ExceptionHandler(Exception.class) 25 | @ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR) 26 | public GenerateResponse internalServerErrorHandle() { 27 | return new GenerateResponse<>(500, "未知错误"); 28 | } 29 | 30 | @ExceptionHandler(ExceptionResponse.class) 31 | public GenerateResponse ExceptionResponseHandle(ExceptionResponse error) { 32 | return new GenerateResponse<>(error.getCode().getCode(), error.getMessage()); 33 | } 34 | 35 | @ExceptionHandler(MethodArgumentNotValidException.class) 36 | public ResponseEntity> methodArgumentNotValidExceptionHandle(MethodArgumentNotValidException error) { 37 | if (!error.getFieldError().getClass().toString().contains(SpringValidatorAdapter.class.toString())) { 38 | return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body(new GenerateResponse<>(500, "未知错误")); 39 | } 40 | return ResponseEntity.status(HttpStatus.OK).body(new GenerateResponse<>(ExceptionResponseCode.PARAMETER_ERROR.getCode(), error.getAllErrors().get(0).getDefaultMessage())); 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /src/main/java/fun/diviner/aidiviner/config/Interceptor/CaptchaInterceptor.java: -------------------------------------------------------------------------------- 1 | package fun.diviner.aidiviner.config.Interceptor; 2 | 3 | import jakarta.servlet.http.HttpServletRequest; 4 | import jakarta.servlet.http.HttpServletResponse; 5 | 6 | import org.springframework.stereotype.Component; 7 | import org.springframework.web.servlet.HandlerInterceptor; 8 | import org.springframework.beans.factory.annotation.Autowired; 9 | 10 | import fun.diviner.aidiviner.redis.CaptchaRedis; 11 | import fun.diviner.aidiviner.util.response.ExceptionResponse; 12 | import fun.diviner.aidiviner.util.response.ExceptionResponseCode; 13 | 14 | @Component 15 | public class CaptchaInterceptor implements HandlerInterceptor { 16 | @Autowired 17 | private CaptchaRedis captcha; 18 | 19 | @Override 20 | public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) { 21 | String key = request.getParameter("captchaKey"); 22 | String code = request.getParameter("captchaCode"); 23 | if (key == null || key.isEmpty() || code == null || code.isEmpty()) { 24 | throw new ExceptionResponse(ExceptionResponseCode.PARAMETER_ERROR, "验证码参数不能为空"); 25 | } 26 | 27 | String correctCaptchaCode = this.captcha.get(key); 28 | if (correctCaptchaCode != null) { 29 | this.captcha.delete(key); 30 | } 31 | if (!code.equalsIgnoreCase(correctCaptchaCode)) { 32 | throw new ExceptionResponse(ExceptionResponseCode.PARAMETER_ERROR, "验证码错误"); 33 | } 34 | return true; 35 | } 36 | } -------------------------------------------------------------------------------- /src/main/java/fun/diviner/aidiviner/config/Interceptor/PreInterceptor.java: -------------------------------------------------------------------------------- 1 | package fun.diviner.aidiviner.config.Interceptor; 2 | 3 | import jakarta.servlet.http.HttpServletRequest; 4 | import jakarta.servlet.http.HttpServletResponse; 5 | 6 | import org.springframework.stereotype.Component; 7 | import org.springframework.web.servlet.HandlerInterceptor; 8 | 9 | @Component 10 | public class PreInterceptor implements HandlerInterceptor { 11 | @Override 12 | public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) { 13 | return !request.getMethod().equalsIgnoreCase("OPTIONS"); 14 | } 15 | } -------------------------------------------------------------------------------- /src/main/java/fun/diviner/aidiviner/config/Interceptor/ToolInterceptor.java: -------------------------------------------------------------------------------- 1 | package fun.diviner.aidiviner.config.Interceptor; 2 | 3 | import jakarta.servlet.http.HttpServletRequest; 4 | import jakarta.servlet.http.HttpServletResponse; 5 | import java.util.Arrays; 6 | 7 | import org.springframework.stereotype.Component; 8 | import org.springframework.web.servlet.HandlerInterceptor; 9 | import org.springframework.beans.factory.annotation.Autowired; 10 | import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; 11 | 12 | import fun.diviner.aidiviner.mapper.ToolMapper; 13 | import fun.diviner.aidiviner.service.UtilService; 14 | import fun.diviner.aidiviner.entity.database.Tool; 15 | import fun.diviner.aidiviner.entity.Trade; 16 | import fun.diviner.aidiviner.entity.Pay; 17 | import fun.diviner.aidiviner.entity.PayType; 18 | import fun.diviner.aidiviner.entity.Special; 19 | import fun.diviner.aidiviner.util.response.ExceptionResponse; 20 | import fun.diviner.aidiviner.util.response.ExceptionResponseCode; 21 | 22 | @Component 23 | public class ToolInterceptor implements HandlerInterceptor { 24 | @Autowired 25 | private ToolMapper tool; 26 | @Autowired 27 | private UtilService util; 28 | 29 | @Override 30 | public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) { 31 | String[] paths = request.getServletPath().split("/"); 32 | String alias = String.join("_", Arrays.copyOfRange(paths, 2, paths.length)); 33 | LambdaQueryWrapper wrapper = new LambdaQueryWrapper<>(); 34 | wrapper.eq(Tool::getAlias, alias); 35 | Tool tool = this.tool.selectOne(wrapper); 36 | if (tool == null) { 37 | throw new ExceptionResponse(ExceptionResponseCode.PARAMETER_ERROR, "工具不存在"); 38 | } else if (this.util.getCoreContent(Special.CoreName.openTool).equals("0")) { 39 | throw new ExceptionResponse(ExceptionResponseCode.RUN_ERROR, "工具因维护暂时关闭"); 40 | } 41 | 42 | Trade trade = new Trade(); 43 | trade.setId(tool.getId()); 44 | Pay pay = this.util.pay(PayType.BALANCE, tool.getPrice()); 45 | if (!pay.isState()) { 46 | throw new ExceptionResponse(ExceptionResponseCode.USER_ERROR, "余额不足"); 47 | } 48 | trade.setPay(pay); 49 | this.util.setAttribute(Special.AttributeName.trade, trade); 50 | return true; 51 | } 52 | } -------------------------------------------------------------------------------- /src/main/java/fun/diviner/aidiviner/config/Interceptor/auth/AuthInterceptor.java: -------------------------------------------------------------------------------- 1 | package fun.diviner.aidiviner.config.Interceptor.auth; 2 | 3 | import jakarta.servlet.http.HttpServletRequest; 4 | import jakarta.servlet.http.HttpServletResponse; 5 | 6 | import org.springframework.stereotype.Component; 7 | import org.springframework.web.servlet.HandlerInterceptor; 8 | import org.springframework.beans.factory.annotation.Autowired; 9 | import io.jsonwebtoken.Claims; 10 | 11 | import fun.diviner.aidiviner.redis.AccessTokenRedis; 12 | import fun.diviner.aidiviner.mapper.UserMapper; 13 | import fun.diviner.aidiviner.service.UtilService; 14 | import fun.diviner.aidiviner.util.response.ExceptionResponse; 15 | import fun.diviner.aidiviner.util.response.ExceptionResponseCode; 16 | import fun.diviner.aidiviner.entity.Special; 17 | import fun.diviner.aidiviner.entity.Auth; 18 | 19 | @Component 20 | public class AuthInterceptor implements HandlerInterceptor { 21 | @Autowired 22 | private AccessTokenRedis accessToken; 23 | @Autowired 24 | private UserMapper user; 25 | @Autowired 26 | private UtilService util; 27 | 28 | @Override 29 | public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) { 30 | String token = request.getHeader("Authorization"); 31 | if (token == null) { 32 | throw new ExceptionResponse(ExceptionResponseCode.PARAMETER_ERROR, "Token不能为空"); 33 | } 34 | 35 | Claims payload; 36 | token = token.replace("Bearer ", ""); 37 | Integer id; 38 | try { 39 | payload = JWTUtil.parser(token); 40 | token = (String) payload.get("token"); 41 | id = this.accessToken.get(token); 42 | if (id == null) { 43 | throw new Exception(); 44 | } else if (this.user.selectById(id) == null) { 45 | this.accessToken.delete(token); 46 | throw new Exception(); 47 | } 48 | } catch (Exception error) { 49 | throw new ExceptionResponse(ExceptionResponseCode.USER_ERROR, "Token错误"); 50 | } 51 | 52 | Auth auth = new Auth(); 53 | auth.setId(id); 54 | auth.setToken(token); 55 | this.util.setAttribute(Special.AttributeName.user, auth); 56 | return true; 57 | } 58 | } -------------------------------------------------------------------------------- /src/main/java/fun/diviner/aidiviner/config/Interceptor/auth/JWTUtil.java: -------------------------------------------------------------------------------- 1 | package fun.diviner.aidiviner.config.Interceptor.auth; 2 | 3 | import javax.crypto.SecretKey; 4 | import java.util.Map; 5 | import java.util.concurrent.TimeUnit; 6 | import java.util.Date; 7 | 8 | import io.jsonwebtoken.security.Keys; 9 | import io.jsonwebtoken.Jwts; 10 | import io.jsonwebtoken.Claims; 11 | 12 | import fun.diviner.aidiviner.entity.Special; 13 | 14 | public class JWTUtil { 15 | private static SecretKey key = Keys.hmacShaKeyFor(Special.authSecret.getBytes()); 16 | 17 | public static String generate(Map payload, int time, TimeUnit unit) { 18 | Date expiration = new Date(new Date().getTime() + unit.toMillis(time)); 19 | return Jwts.builder().claims(payload).expiration(expiration).signWith(JWTUtil.key).compact(); 20 | } 21 | 22 | public static Claims parser(String token) { 23 | return Jwts.parser().verifyWith(JWTUtil.key).build().parseSignedClaims(token).getPayload(); 24 | } 25 | } -------------------------------------------------------------------------------- /src/main/java/fun/diviner/aidiviner/config/MyBatisConfig.java: -------------------------------------------------------------------------------- 1 | package fun.diviner.aidiviner.config; 2 | 3 | import org.springframework.context.annotation.Configuration; 4 | import org.springframework.context.annotation.Bean; 5 | import org.mybatis.spring.annotation.MapperScan; 6 | import com.baomidou.mybatisplus.extension.plugins.MybatisPlusInterceptor; 7 | import com.baomidou.mybatisplus.extension.plugins.inner.PaginationInnerInterceptor; 8 | 9 | @Configuration 10 | @MapperScan("fun.diviner") 11 | public class MyBatisConfig { 12 | @Bean 13 | public MybatisPlusInterceptor mybatisPlusPageInterceptorBean() { 14 | MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor(); 15 | interceptor.addInnerInterceptor(new PaginationInnerInterceptor()); 16 | return interceptor; 17 | } 18 | } -------------------------------------------------------------------------------- /src/main/java/fun/diviner/aidiviner/config/RedisConfig.java: -------------------------------------------------------------------------------- 1 | package fun.diviner.aidiviner.config; 2 | 3 | import org.springframework.context.annotation.Configuration; 4 | import org.springframework.context.annotation.Primary; 5 | import org.springframework.context.annotation.Bean; 6 | import org.springframework.beans.factory.annotation.Autowired; 7 | import org.springframework.boot.autoconfigure.data.redis.RedisProperties; 8 | import org.springframework.data.redis.connection.lettuce.LettuceConnectionFactory; 9 | import org.springframework.data.redis.connection.RedisStandaloneConfiguration; 10 | import org.springframework.data.redis.core.RedisTemplate; 11 | import org.springframework.data.redis.serializer.StringRedisSerializer; 12 | import org.springframework.data.redis.serializer.GenericToStringSerializer; 13 | 14 | @Configuration 15 | public class RedisConfig { 16 | @Autowired 17 | private RedisProperties property; 18 | 19 | private LettuceConnectionFactory getFactory(int index) { 20 | RedisStandaloneConfiguration config = new RedisStandaloneConfiguration(); 21 | config.setHostName(this.property.getHost()); 22 | config.setPort(this.property.getPort()); 23 | config.setPassword(this.property.getPassword()); 24 | config.setDatabase(index); 25 | return new LettuceConnectionFactory(config); 26 | } 27 | 28 | private RedisTemplate getTemplate(LettuceConnectionFactory factory, Class type) { 29 | RedisTemplate template = new RedisTemplate<>(); 30 | template.setConnectionFactory(factory); 31 | template.setKeySerializer(new StringRedisSerializer()); 32 | template.setValueSerializer(new GenericToStringSerializer<>(type)); 33 | return template; 34 | } 35 | 36 | @Primary 37 | @Bean 38 | public LettuceConnectionFactory captchaRedisFactoryBean() { 39 | return this.getFactory(0); 40 | } 41 | 42 | @Bean 43 | public RedisTemplate captchaRedisBean() { 44 | return this.getTemplate(this.captchaRedisFactoryBean(), String.class); 45 | } 46 | 47 | @Bean 48 | public LettuceConnectionFactory accessTokenRedisFactoryBean() { 49 | return this.getFactory(2); 50 | } 51 | 52 | @Bean 53 | public RedisTemplate accessTokenRedisBean() { 54 | return this.getTemplate(this.accessTokenRedisFactoryBean(), Integer.class); 55 | } 56 | } -------------------------------------------------------------------------------- /src/main/java/fun/diviner/aidiviner/config/ScheduleConfig.java: -------------------------------------------------------------------------------- 1 | package fun.diviner.aidiviner.config; 2 | 3 | import java.time.LocalDateTime; 4 | 5 | import org.springframework.stereotype.Component; 6 | import org.springframework.scheduling.annotation.EnableScheduling; 7 | import org.springframework.scheduling.annotation.Scheduled; 8 | import org.springframework.beans.factory.annotation.Autowired; 9 | import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper; 10 | 11 | import fun.diviner.aidiviner.mapper.UserMapper; 12 | import fun.diviner.aidiviner.entity.database.User; 13 | import fun.diviner.aidiviner.entity.Special; 14 | 15 | @Component 16 | @EnableScheduling 17 | public class ScheduleConfig { 18 | @Autowired 19 | private UserMapper user; 20 | 21 | @Scheduled(cron="0 0 0 * * *") 22 | private void resetUser() { 23 | LambdaUpdateWrapper wrapper = new LambdaUpdateWrapper<>(); 24 | wrapper.eq(User::isCheckIn, true); 25 | wrapper.set(User::isCheckIn, false); 26 | this.user.update(null, wrapper); 27 | } 28 | 29 | @Scheduled(cron="0 */10 * * * *") 30 | private void checkUser() { 31 | LambdaUpdateWrapper wrapper = new LambdaUpdateWrapper<>(); 32 | wrapper.le(User::getGroupExpirationTime, LocalDateTime.now()); 33 | wrapper.set(User::getGroupId, Special.commonGroupId); 34 | wrapper.set(User::getGroupExpirationTime, null); 35 | this.user.update(null, wrapper); 36 | } 37 | } -------------------------------------------------------------------------------- /src/main/java/fun/diviner/aidiviner/config/WebConfig.java: -------------------------------------------------------------------------------- 1 | package fun.diviner.aidiviner.config; 2 | 3 | import org.springframework.context.annotation.Configuration; 4 | import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; 5 | import org.springframework.web.servlet.config.annotation.CorsRegistry; 6 | import org.springframework.web.servlet.config.annotation.InterceptorRegistry; 7 | import org.springframework.beans.factory.annotation.Autowired; 8 | 9 | import fun.diviner.aidiviner.config.Interceptor.CaptchaInterceptor; 10 | import fun.diviner.aidiviner.config.Interceptor.auth.AuthInterceptor; 11 | import fun.diviner.aidiviner.config.Interceptor.ToolInterceptor; 12 | import fun.diviner.aidiviner.config.Interceptor.PreInterceptor; 13 | 14 | @Configuration 15 | public class WebConfig implements WebMvcConfigurer { 16 | @Autowired 17 | private PreInterceptor pre; 18 | @Autowired 19 | private CaptchaInterceptor captcha; 20 | @Autowired 21 | private AuthInterceptor auth; 22 | @Autowired 23 | private ToolInterceptor tool; 24 | 25 | @Override 26 | public void addCorsMappings(CorsRegistry registry) { 27 | registry.addMapping("/**").allowedOrigins("*").allowedMethods("*").allowedHeaders("*"); 28 | } 29 | 30 | @Override 31 | public void addInterceptors(InterceptorRegistry registry) { 32 | registry.addInterceptor(this.pre).addPathPatterns("/**"); 33 | registry.addInterceptor(this.captcha).addPathPatterns("/user/register_login"); 34 | registry.addInterceptor(this.auth).addPathPatterns("/user/**", "/tool/**").excludePathPatterns("/user/register_login"); 35 | registry.addInterceptor(this.tool).addPathPatterns("/tool/**"); 36 | } 37 | } -------------------------------------------------------------------------------- /src/main/java/fun/diviner/aidiviner/controller/CommonController.java: -------------------------------------------------------------------------------- 1 | package fun.diviner.aidiviner.controller; 2 | 3 | import java.util.Map; 4 | import java.util.List; 5 | 6 | import org.springframework.web.bind.annotation.RestController; 7 | import org.springframework.web.bind.annotation.RequestMapping; 8 | import org.springframework.web.bind.annotation.GetMapping; 9 | import org.springframework.web.bind.annotation.RequestParam; 10 | import org.springframework.beans.factory.annotation.Autowired; 11 | import org.springframework.validation.annotation.Validated; 12 | 13 | import fun.diviner.aidiviner.service.CommonService; 14 | import fun.diviner.aidiviner.util.response.GenerateResponse; 15 | import fun.diviner.aidiviner.entity.database.Tool; 16 | import fun.diviner.aidiviner.dto.common.GetRecordIdParameter; 17 | import fun.diviner.aidiviner.dto.common.GetRecordParameter; 18 | 19 | @RestController 20 | @RequestMapping("/common") 21 | public class CommonController { 22 | @Autowired 23 | private CommonService service; 24 | 25 | @GetMapping("/get_captcha") 26 | public GenerateResponse> getCaptcha() { 27 | return this.service.getCaptcha(); 28 | } 29 | 30 | @GetMapping("/get_tool") 31 | public GenerateResponse> getTool() { 32 | return this.service.getTool(); 33 | } 34 | 35 | @GetMapping("/get_vip") 36 | public GenerateResponse>> getVIP() { 37 | return this.service.getVIP(); 38 | } 39 | 40 | @GetMapping("/yi_pay_callback") 41 | public GenerateResponse yiPayCallback(@RequestParam Map parameter) { 42 | return this.service.yiPayCallback(parameter); 43 | } 44 | 45 | @GetMapping("/get_record_id") 46 | public GenerateResponse> getRecordUUID(@Validated GetRecordIdParameter parameter) { 47 | return this.service.getRecordId(parameter); 48 | } 49 | 50 | @GetMapping("/get_record") 51 | public GenerateResponse> getRecord(@Validated GetRecordParameter parameter) { 52 | return this.service.getRecord(parameter); 53 | } 54 | } -------------------------------------------------------------------------------- /src/main/java/fun/diviner/aidiviner/controller/ToolController.java: -------------------------------------------------------------------------------- 1 | package fun.diviner.aidiviner.controller; 2 | 3 | import org.springframework.web.bind.annotation.RestController; 4 | import org.springframework.web.bind.annotation.RequestMapping; 5 | import org.springframework.web.bind.annotation.PostMapping; 6 | import org.springframework.web.bind.annotation.RequestBody; 7 | import org.springframework.beans.factory.annotation.Autowired; 8 | import org.springframework.validation.annotation.Validated; 9 | 10 | import fun.diviner.aidiviner.service.tool.TarotService; 11 | import fun.diviner.aidiviner.service.tool.BaZiService; 12 | import fun.diviner.aidiviner.service.tool.MeiHuaService; 13 | import fun.diviner.aidiviner.util.response.GenerateResponse; 14 | import fun.diviner.aidiviner.diviner.type.TarotResponse; 15 | import fun.diviner.aidiviner.diviner.type.BaZiArrangeResponse; 16 | import fun.diviner.aidiviner.diviner.type.MeiHuaArrangeResponse; 17 | import fun.diviner.aidiviner.dto.tool.tarot.TarotCommonParameter; 18 | import fun.diviner.aidiviner.dto.tool.tarot.TarotSelectParameter; 19 | import fun.diviner.aidiviner.dto.tool.bazi.BaZiArrangeParameter; 20 | import fun.diviner.aidiviner.dto.tool.bazi.BaZiSolveParameter; 21 | import fun.diviner.aidiviner.dto.tool.meihua.MeiHuaArrangeParameter; 22 | import fun.diviner.aidiviner.dto.tool.meihua.MeiHuaSolveParameter; 23 | 24 | @RestController 25 | @RequestMapping("/tool") 26 | public class ToolController { 27 | @Autowired 28 | private TarotService tarot; 29 | @Autowired 30 | private BaZiService baZi; 31 | @Autowired 32 | private MeiHuaService meiHua; 33 | 34 | @PostMapping("/tarot/common") 35 | public GenerateResponse tarotCommon(@RequestBody @Validated TarotCommonParameter parameter) { 36 | return this.tarot.common(parameter, false); 37 | } 38 | 39 | @PostMapping("/tarot/select") 40 | public GenerateResponse tarotSelect(@RequestBody @Validated TarotSelectParameter parameter) { 41 | return this.tarot.select(parameter, false); 42 | } 43 | 44 | @PostMapping("/tarot/common_pro") 45 | public GenerateResponse tarotCommonPro(@RequestBody @Validated TarotCommonParameter parameter) { 46 | return this.tarot.common(parameter, true); 47 | } 48 | 49 | @PostMapping("/tarot/select_pro") 50 | public GenerateResponse tarotSelectPro(@RequestBody @Validated TarotSelectParameter parameter) { 51 | return this.tarot.select(parameter, true); 52 | } 53 | 54 | @PostMapping("/bazi/arrange") 55 | public GenerateResponse baZiArrange(@RequestBody @Validated BaZiArrangeParameter parameter) { 56 | return this.baZi.arrange(parameter); 57 | } 58 | 59 | @PostMapping("/bazi/solve") 60 | public GenerateResponse baZiSolve(@RequestBody @Validated BaZiSolveParameter parameter) { 61 | return this.baZi.solve(parameter); 62 | } 63 | 64 | @PostMapping("/meihua/arrange") 65 | public GenerateResponse meiHuaArrange(@RequestBody @Validated MeiHuaArrangeParameter parameter) { 66 | return this.meiHua.arrange(parameter); 67 | } 68 | 69 | @PostMapping("/meihua/solve") 70 | public GenerateResponse meiHuaSolve(@RequestBody @Validated MeiHuaSolveParameter parameter) { 71 | return this.meiHua.solve(parameter); 72 | } 73 | } -------------------------------------------------------------------------------- /src/main/java/fun/diviner/aidiviner/controller/UserController.java: -------------------------------------------------------------------------------- 1 | package fun.diviner.aidiviner.controller; 2 | 3 | import java.util.Map; 4 | 5 | import org.springframework.web.bind.annotation.RestController; 6 | import org.springframework.web.bind.annotation.RequestMapping; 7 | import org.springframework.web.bind.annotation.PostMapping; 8 | import org.springframework.web.bind.annotation.GetMapping; 9 | import org.springframework.web.bind.annotation.RequestBody; 10 | import org.springframework.beans.factory.annotation.Autowired; 11 | import org.springframework.validation.annotation.Validated; 12 | 13 | import fun.diviner.aidiviner.service.UserService; 14 | import fun.diviner.aidiviner.util.response.GenerateResponse; 15 | import fun.diviner.aidiviner.util.response.ExceptionResponse; 16 | import fun.diviner.aidiviner.util.response.ExceptionResponseCode; 17 | import fun.diviner.aidiviner.dto.user.RegisterLoginParameter; 18 | import fun.diviner.aidiviner.dto.user.ModifyAccountParameter; 19 | import fun.diviner.aidiviner.dto.user.OpenVIPParameter; 20 | import fun.diviner.aidiviner.dto.user.RechargeParameter; 21 | import fun.diviner.aidiviner.dto.user.GetRechargeParameter; 22 | import fun.diviner.aidiviner.dto.user.GetRecordParameter; 23 | import fun.diviner.aidiviner.dto.user.UseCardParameter; 24 | import fun.diviner.aidiviner.entity.Special; 25 | 26 | @RestController 27 | @RequestMapping("/user") 28 | public class UserController { 29 | @Autowired 30 | private UserService service; 31 | 32 | @PostMapping("/register_login") 33 | public GenerateResponse> registerLogin(@RequestBody @Validated RegisterLoginParameter parameter) { 34 | return this.service.registerLogin(parameter); 35 | } 36 | 37 | @GetMapping("/logout") 38 | public GenerateResponse logout() { 39 | return this.service.logout(); 40 | } 41 | 42 | @GetMapping("/get_base_information") 43 | public GenerateResponse> getBaseInformation() { 44 | return this.service.getBaseInformation(); 45 | } 46 | 47 | @PostMapping("/modify_account") 48 | public GenerateResponse modifyAccount(@RequestBody @Validated ModifyAccountParameter parameter) { 49 | return this.service.modifyAccount(parameter); 50 | } 51 | 52 | @GetMapping("/check_in") 53 | public GenerateResponse checkIn() { 54 | return this.service.checkIn(); 55 | } 56 | 57 | @PostMapping("/open_vip") 58 | public GenerateResponse openVIP(@RequestBody @Validated OpenVIPParameter parameter) { 59 | int id = parameter.getId(); 60 | if (id == Special.commonGroupId) { 61 | throw new ExceptionResponse(ExceptionResponseCode.PARAMETER_ERROR, "ID不能为" + Special.commonGroupId); 62 | } 63 | 64 | return this.service.openVIP(parameter); 65 | } 66 | 67 | @PostMapping("/recharge") 68 | public GenerateResponse recharge(@RequestBody @Validated RechargeParameter parameter) { 69 | return this.service.recharge(parameter); 70 | } 71 | 72 | @GetMapping("/get_recharge") 73 | public GenerateResponse> getRecharge(@Validated GetRechargeParameter parameter) { 74 | return this.service.getRecharge(parameter); 75 | } 76 | 77 | @GetMapping("/get_record") 78 | public GenerateResponse> getRecord(@Validated GetRecordParameter parameter) { 79 | return this.service.getRecord(parameter); 80 | } 81 | 82 | @PostMapping("/use_card") 83 | public GenerateResponse useCard(@RequestBody @Validated UseCardParameter parameter) { 84 | return this.service.useCard(parameter); 85 | } 86 | } -------------------------------------------------------------------------------- /src/main/java/fun/diviner/aidiviner/diviner/BaZi.java: -------------------------------------------------------------------------------- 1 | package fun.diviner.aidiviner.diviner; 2 | 3 | import java.util.Calendar; 4 | import java.util.Date; 5 | import java.util.TimeZone; 6 | 7 | import fun.diviner.aidiviner.diviner.ai.AIModel; 8 | import fun.diviner.aidiviner.diviner.ai.AIRequestUtil; 9 | import fun.diviner.aidiviner.diviner.bazi.BaZiSetting; 10 | import fun.diviner.aidiviner.diviner.bazi.BaZiTool; 11 | import fun.diviner.aidiviner.dto.tool.bazi.BaZiArrangeParameter; 12 | import fun.diviner.aidiviner.dto.tool.bazi.BaZiSolveParameter; 13 | 14 | /** 15 | * @author Coaixy 16 | * @createTime 2025-01-23 17 | * @packageName fun.diviner.diviner 18 | **/ 19 | 20 | 21 | public class BaZi { 22 | public static String getAIResponse(BaZiSolveParameter obj) { 23 | String prompt = ""; 24 | if (!obj.getDayun().equalsIgnoreCase("") && !obj.getLiunian().equalsIgnoreCase("")) { 25 | prompt = "你是一个命理大师 请你解析八字 %s %s 在 %s 大运 %s 流年的利弊 并给出合适的建议".formatted( 26 | obj.getBazi(), obj.getGender(), obj.getDayun(), obj.getLiunian() 27 | ); 28 | } else { 29 | prompt = "你是一个命理大师 请你解析八字 %s %s给出层次如何 不需要进行大运的解析 但给出适合的大运流年 最后给出一首诗来" 30 | .formatted(obj.getBazi(), obj.getGender()); 31 | } 32 | return AIRequestUtil.getAIResponse(prompt, AIModel.DEEPSEEK_REPONSER).getContent(); 33 | } 34 | 35 | public static BaZiTool getBaZiObj(BaZiArrangeParameter parameter) { 36 | BaZiSetting baZiSetting = new BaZiSetting(); 37 | 38 | Calendar calendar = Calendar.getInstance(TimeZone.getTimeZone("Asia/Shanghai")); 39 | calendar.set(parameter.getYear(), parameter.getMonth() - 1, parameter.getDay(), 40 | parameter.getHour(), parameter.getMinute()); 41 | Date date = calendar.getTime(); 42 | 43 | baZiSetting.setName(null); 44 | baZiSetting.setDateType(0); 45 | baZiSetting.setDate(date); 46 | baZiSetting.setSex("男".equals(parameter.getGender()) ? 1 : 0); 47 | 48 | BaZiTool baZiTool = new BaZiTool(baZiSetting); 49 | baZiTool.setLunar(null); 50 | baZiTool.setSolar(null); 51 | return baZiTool; 52 | } 53 | } -------------------------------------------------------------------------------- /src/main/java/fun/diviner/aidiviner/diviner/MeiHua.java: -------------------------------------------------------------------------------- 1 | package fun.diviner.aidiviner.diviner; 2 | 3 | import fun.diviner.aidiviner.diviner.ai.AIModel; 4 | import fun.diviner.aidiviner.diviner.ai.AIRequestUtil; 5 | import fun.diviner.aidiviner.diviner.type.MeiHuaArrangeResponse; 6 | 7 | /** 8 | * @author Coaixy 9 | * @createTime 2025-01-25 10 | * @packageName fun.diviner.diviner 11 | **/ 12 | 13 | public class MeiHua { 14 | public static String getAIResponse(MeiHuaArrangeResponse arrangeResponse, String question) { 15 | String prompt = """ 16 | 你是一个梅花易数大师 17 | 请你帮我解析以下梅花易数排盘结果 18 | 时间: %s 19 | 卦局: %s 变 %s 20 | 问题: %s 21 | """.formatted(arrangeResponse.getBazi(), arrangeResponse.getBen().getName(), arrangeResponse.getBian().getName(), question); 22 | 23 | return AIRequestUtil.getAIResponse(prompt, AIModel.DEEPSEEK_REPONSER).getContent(); 24 | } 25 | } -------------------------------------------------------------------------------- /src/main/java/fun/diviner/aidiviner/diviner/Tarot.java: -------------------------------------------------------------------------------- 1 | package fun.diviner.aidiviner.diviner; 2 | 3 | import java.util.ArrayList; 4 | import java.util.List; 5 | import java.util.Random; 6 | 7 | import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; 8 | import org.springframework.beans.factory.annotation.Autowired; 9 | import org.springframework.stereotype.Component; 10 | 11 | import fun.diviner.aidiviner.diviner.ai.AIModel; 12 | import fun.diviner.aidiviner.diviner.type.TarotResponse; 13 | import fun.diviner.aidiviner.entity.database.ToolTarotCard; 14 | import fun.diviner.aidiviner.entity.database.ToolTarotSpread; 15 | import fun.diviner.aidiviner.mapper.ToolTarotCardMapper; 16 | import fun.diviner.aidiviner.mapper.ToolTarotSpreadMapper; 17 | import fun.diviner.aidiviner.util.response.ExceptionResponse; 18 | import fun.diviner.aidiviner.util.response.ExceptionResponseCode; 19 | import fun.diviner.aidiviner.diviner.ai.AIRequestUtil; 20 | 21 | /** 22 | * @author Coaixy 23 | * @createTime 2025-01-24 24 | * @packageName fun.diviner.diviner 25 | **/ 26 | 27 | @Component 28 | public class Tarot { 29 | @Autowired 30 | private ToolTarotCardMapper tarotCardMapper; 31 | @Autowired 32 | private ToolTarotSpreadMapper tarotSpreadMapper; 33 | 34 | /** 35 | * 塔罗牌信息 36 | * 37 | * @param name 38 | * @param description 39 | * @param meaning 40 | */ 41 | public record TarotCardRecord(String name, String description, String meaning) { 42 | @Override 43 | public String toString() { 44 | return """ 45 | %s 46 | %s 47 | %s 48 | """.formatted(name, description, meaning); 49 | } 50 | } 51 | 52 | /** 53 | * 获取塔罗牌牌阵 54 | * 55 | * @param question 问题 56 | * @return 塔罗牌牌阵 57 | */ 58 | public String getTarotSpread(String question) { 59 | String prompt = """ 60 | # Role: 塔罗牌阵选择助手 61 | 62 | ## Skill 63 | 1.擅长概括与归纳,理解问题大意 64 | 2.擅长塔罗牌的相关概念 包括牌意和牌阵 65 | 66 | ## Definition 67 | 1. 三张牌占卜法 68 | 通用型占卜牌阵,可以自由定义 69 | 应用在很多场合,不受约束的占卜相关事物 70 | 或用来分析独立事情的某个方面 特殊:每日运势 71 | 可以用于暗恋 72 | 2. 时间流牌阵 73 | 平行流向的时间解析法,纯粹的时间流向 74 | 应用于空间维度上的时间占卜 75 | 恍若流淌的时间从过去延伸到未来 76 | 事件平铺于时间毯之上 77 | 3. 圣三角牌阵 78 | 梳理问题前因后果,是时间流的变形 79 | 更注重事物内在原因,而非单纯时间流向 80 | 尤其适合根据因由来判断事物 81 | 4. 四元素牌阵 82 | 通过四元素了解问题多方面的状况 83 | 从感性、理性、物质、行动四方面透彻审视 84 | 多重角度出发,进而了解问题实质 85 | 5. 恋人金字塔 86 | 简洁直接,涵盖两人相恋原始要素 87 | 适合*恋人情侣*间的占卜,牌面一出明了易懂 88 | 是占卜爱情方面常用的牌阵 非情侣关系不要选择 89 | 6. 爱情大十字 90 | 注重内心情感,主要应用于情侣之间 91 | 善于洞悉彼此关系中的情感状况并分析结果 92 | 7. 寻找对象牌阵 93 | 本牌阵适合单身人士占卜,可用来健全意中人的愿景,帮助自己确定目标. 94 | 不知道自己想要什么,不妨问一问这个牌阵吧. 95 | 8. 爱情树牌阵 适合溯本求源 & 寻找症结 96 | 本牌阵适合恋爱遇到困境时做占卜,寻找潜在原因,改善感情关系. 97 | 当你遇到感情困境,可用本牌阵突出重围. 98 | 9. 吉普赛牌阵 99 | 本牌阵适合婚姻 爱情 恋爱 感情方面的占卜,探索彼此内心想法,找到合适的相处方式. 100 | 浪漫、奔放的吉普赛牌阵,是你释放情感困兽的首选. 101 | 10. 二选一牌阵 102 | 本牌阵适合在两种情况中选择其中一种,可用于感情、事业、学业方面的占卜,用途相对广泛. 103 | 在自己犹豫不决的时候,二选一牌阵是你最棒的选择. 104 | 11. 财富之数 105 | 本牌阵像征财富的生成,可揭示财富脉搏,对求财有积极的指导意义. 106 | 如果你想了解自己的财富指数,尝试下这个牌阵吧. 107 | 12. 维纳斯牌阵 108 | 本牌阵适合婚姻,恋爱方面的未来指向占卜,是分析爱情未来的牌阵,可以看到双方未来的状况. 109 | 如果你想占卜自己爱情的未来,维纳斯牌阵是首推的选择. 110 | 13. 周运势牌阵 111 | 本牌阵是周运占卜的专用牌阵,适用于周运占卜,可以占卜下一周的运势. 112 | 亦可以应用在有七天期限的占卜中,不影响效果. 113 | 14. 六芒星牌阵 114 | 本牌阵判断事情走向,有积极的指导意义,可分析潜意识与显意识的表达,有着极强的窥视未来能力. 115 | 如果你想真正的预测未来,仔细分析、了解、感受六芒星牌阵吧. 116 | 15. 情人复合牌阵 117 | 得不到的永远在骚动,被偏爱的都有恃无恐,通过对照彼此内心感受,揭开对方扑朔迷离的面纱. 118 | 如果你仍念念不忘,觉得彼此前缘未了,打开这个牌阵吧. 119 | 120 | ## Rules 121 | 1. 只能选择Definition 中的牌阵 122 | 2. 如果有合适的牌阵请直接回复牌阵名 不需要给出原因 123 | 124 | ## Workflow 125 | 1. 等待用户输入问题 126 | 2. 根据Rules给出答案 127 | 128 | 问题为: 129 | """ + question; 130 | return AIRequestUtil.getAIResponse(prompt, AIModel.GLM_FLASH).getContent(); 131 | } 132 | 133 | /** 134 | * 获取塔罗牌需要的牌数 135 | * 136 | * @param spreadName 牌阵名 137 | * @return 需要的牌数 138 | */ 139 | public int getTarotNeedNum(String spreadName) { 140 | QueryWrapper queryWrapper = new QueryWrapper<>(); 141 | queryWrapper.eq("name", spreadName); 142 | ToolTarotSpread tarotSpread = tarotSpreadMapper.selectOne(queryWrapper); 143 | return tarotSpread.getCard().split("\\.").length - 1; 144 | } 145 | 146 | /** 147 | * 获取塔罗牌列表 148 | * 149 | * @param indexList 索引列表 150 | * @return 塔罗牌列表 151 | */ 152 | public List getTarotCardList(List indexList) { 153 | List result = new ArrayList<>(List.of()); 154 | for (int i : indexList) { 155 | ToolTarotCard tarotCard = tarotCardMapper.selectById(Math.abs(i)); 156 | if (i < 0) { 157 | result.add(new TarotCardRecord(tarotCard.getName().replaceAll("[a-zA-Z]", "") + "逆位", tarotCard.getDescription(), tarotCard.getReversed())); 158 | } else { 159 | result.add(new TarotCardRecord(tarotCard.getName().replaceAll("[a-zA-Z]", ""), tarotCard.getDescription(), tarotCard.getNormal())); 160 | } 161 | } 162 | return result; 163 | } 164 | 165 | /** 166 | * 获取结果 167 | * 168 | * @param question 问题 169 | * @param spreadName 牌阵名 170 | * @param num 牌数 171 | * @return 答案 172 | */ 173 | public TarotResponse getTarotAnswer(String question, String spreadName, int num, boolean isPro) { 174 | ArrayList tarotCards = new ArrayList<>(); 175 | ArrayList reverseList = new ArrayList<>(); 176 | TarotResponse result = new TarotResponse(); 177 | Random random = new Random(); 178 | Random reverseRandom = new Random(); 179 | ArrayList cardIndex = new java.util.ArrayList<>(List.of()); 180 | for (int i = 0; i < num; i++) { 181 | int index = random.nextInt(79) + 1; 182 | if (cardIndex.contains(index)) { 183 | i--; 184 | } else { 185 | cardIndex.add(index); 186 | } 187 | } 188 | for (int i : cardIndex) { 189 | if (reverseRandom.nextBoolean()) { 190 | tarotCards.add(tarotCardMapper.selectById(i)); 191 | reverseList.add(true); 192 | } else { 193 | tarotCards.add(tarotCardMapper.selectById(i)); 194 | reverseList.add(false); 195 | } 196 | } 197 | 198 | result.setQuestion(question); 199 | result.setSpreadName(spreadName); 200 | result.setCardList(tarotCards); 201 | result.setReverseList(reverseList); 202 | result.setAnswer(generateResult(question, tarotCards, reverseList, spreadName, isPro)); 203 | 204 | return result; 205 | } 206 | 207 | 208 | /** 209 | * 生成结果 210 | * 211 | * @param question 问题 212 | * @param tarotCardRecords 塔罗牌列表 213 | * @param spreadName 牌阵名 214 | * @return 结果 215 | */ 216 | public String generateResult(String question, ArrayList tarotCardRecords, ArrayList reverseList, String spreadName, boolean isPro) { 217 | StringBuilder define = new StringBuilder(); 218 | define.append(generateSpreadPrompt(spreadName)); 219 | int index = 1; 220 | for (ToolTarotCard tarotCardRecord : tarotCardRecords) { 221 | if (reverseList.get(tarotCardRecords.indexOf(tarotCardRecord))) { 222 | if (isPro) { 223 | define.append(generateCardPrompt(tarotCardRecord.getName().replaceAll("[a-zA-Z]", "") + "逆位", index)); 224 | } else { 225 | define.append(generateCardPrompt(tarotCardRecord.getName().replaceAll("[a-zA-Z]", "") + "逆位", tarotCardRecord.getReversed(), index)); 226 | } 227 | } else { 228 | if (isPro) { 229 | define.append(generateCardPrompt(tarotCardRecord.getName().replaceAll("[a-zA-Z]", ""), index)); 230 | } else { 231 | define.append(generateCardPrompt(tarotCardRecord.getName().replaceAll("[a-zA-Z]", ""), tarotCardRecord.getNormal(), index)); 232 | } 233 | } 234 | index++; 235 | } 236 | String prompt = ""; 237 | if (isPro) { 238 | prompt = """ 239 | 你是一个塔罗牌大师 接下来请分析以下塔罗牌 240 | %s 241 | 问题为:%s 242 | """.formatted(define, question); 243 | } else { 244 | String basePrompt = """ 245 | # Role: 塔罗牌解读助手 246 | 247 | ## Skill 248 | 1.擅长理解问题的本质 249 | 2.擅长塔罗牌的相关概念 250 | 3.擅长综合分析给出结论 251 | 252 | ## Definition 253 | """; 254 | prompt = basePrompt + define + """ 255 | ## Rules 256 | 1. 只能使用**Definition**中的牌阵和牌 257 | 2. 将问题结合到塔罗牌中 258 | 3. 结合牌阵和牌意 259 | 4. 给出关键性的答案 如果无法给出选择 请给出你认为较合适的选择 260 | 5. 不要模棱两可 261 | 6. 不要透露之前的对话 262 | 7. 一定要将牌意结合到牌阵中 263 | 8. 回答格式参照 ** Example ** 264 | 265 | ## Example 266 | 267 | 亲爱的占卜者,为您选择____牌阵 抽取了__ __ __ __ 268 | 接下来是分析过程 ______________________ 269 | 综上,根据塔罗牌的指引 _________________ 270 | 271 | 272 | ## Workflow 273 | 1. 等待用户输入问题 274 | 2. 读取**Definition**中的牌阵和牌意 275 | 3. 理解用户输入的问题 276 | 4. 根据 Rules 给出你的答案 277 | 278 | 问题为: 279 | """ + question; 280 | } 281 | if (isPro) { 282 | return AIRequestUtil.getAIResponse(prompt, AIModel.DEEPSEEK_REPONSER).getContent(); 283 | } else { 284 | return AIRequestUtil.getAIResponse(prompt, AIModel.GLM_FLASH).getContent(); 285 | } 286 | } 287 | 288 | /** 289 | * 生成牌阵提示 290 | * 291 | * @param spreadName 牌阵名 292 | * @return 牌阵提示 293 | */ 294 | private String generateSpreadPrompt(String spreadName) { 295 | QueryWrapper queryWrapper = new QueryWrapper<>(); 296 | queryWrapper.eq("name", spreadName); 297 | ToolTarotSpread tarotSpread = tarotSpreadMapper.selectOne(queryWrapper); 298 | return """ 299 | - 牌阵名: %s 300 | - 牌阵每张牌所代表的方面: \n %s 301 | - 放入牌阵的分别为: 302 | """.formatted(tarotSpread.getName(), tarotSpread.getCard()); 303 | } 304 | 305 | /** 306 | * 生成牌提示 307 | * 308 | * @param cardName 牌名 309 | * @param meaning 含义 310 | * @return 牌提示 311 | */ 312 | private String generateCardPrompt(String cardName, String meaning, int index) { 313 | return """ 314 | - 第 %s 张 牌名:%s 含义:%s 315 | """.formatted(index, cardName, meaning); 316 | } 317 | 318 | /** 319 | * 生成牌提示 用于Pro 320 | * 321 | * @param cardName 牌名 322 | * @return 牌提示 323 | */ 324 | private String generateCardPrompt(String cardName, int index) { 325 | return """ 326 | - 第 %s 张 牌名:%s 327 | """.formatted(index, cardName); 328 | } 329 | 330 | public TarotResponse getTarotAnswerBySelectIndex(String question, String spreadName, List cardIndexList, boolean isPro) { 331 | try { 332 | QueryWrapper queryWrapper = new QueryWrapper<>(); 333 | queryWrapper.eq("name", spreadName); 334 | ToolTarotSpread tarotSpread = tarotSpreadMapper.selectOne(queryWrapper); 335 | 336 | if (tarotSpread == null) { 337 | throw new ExceptionResponse(ExceptionResponseCode.RUN_ERROR, "牌阵不存在"); 338 | } 339 | if (cardIndexList.size() != tarotSpread.getCard().split("\\.").length - 1) { 340 | throw new ExceptionResponse(ExceptionResponseCode.RUN_ERROR, "牌数不符合牌阵要求"); 341 | } 342 | 343 | ArrayList tarotCards = new ArrayList<>(); 344 | ArrayList reverseList = new ArrayList<>(); 345 | TarotResponse result = new TarotResponse(); 346 | for (int i : cardIndexList) { 347 | if (i < 0) { 348 | tarotCards.add(tarotCardMapper.selectById(-i)); 349 | reverseList.add(true); 350 | } else { 351 | tarotCards.add(tarotCardMapper.selectById(i)); 352 | reverseList.add(false); 353 | } 354 | } 355 | 356 | String answer = generateResult(question, tarotCards, reverseList, spreadName, isPro); 357 | 358 | result.setQuestion(question); 359 | result.setSpreadName(spreadName); 360 | result.setCardList(tarotCards); 361 | result.setReverseList(reverseList); 362 | result.setAnswer(answer); 363 | 364 | return result; 365 | } catch (Exception error) { 366 | throw new ExceptionResponse(ExceptionResponseCode.RUN_ERROR, "这个问题我不能回答你"); 367 | } 368 | } 369 | } -------------------------------------------------------------------------------- /src/main/java/fun/diviner/aidiviner/diviner/ai/AIModel.java: -------------------------------------------------------------------------------- 1 | package fun.diviner.aidiviner.diviner.ai; 2 | 3 | import lombok.Getter; 4 | 5 | /** 6 | * @author Coaixy 7 | * @createTime 2025-01-23 8 | * @packageName fun.diviner.diviner.Ai 9 | **/ 10 | 11 | 12 | @Getter 13 | public enum AIModel { 14 | DEEPSEEK_REPONSER( 15 | "deepseek-reasoner", 16 | "https://api.deepseek.com", 17 | "" 18 | ), 19 | GLM_FLASH( 20 | "glm-4-flash", 21 | "https://open.bigmodel.cn/api/paas/v4/", 22 | "" 23 | ); 24 | 25 | private final String modelName; 26 | private final String baseApi; 27 | private final String key; 28 | 29 | AIModel(String modelName, String baseApi, String key) { 30 | this.modelName = modelName; 31 | this.baseApi = baseApi; 32 | this.key = key; 33 | } 34 | 35 | } -------------------------------------------------------------------------------- /src/main/java/fun/diviner/aidiviner/diviner/ai/AIRequestUtil.java: -------------------------------------------------------------------------------- 1 | package fun.diviner.aidiviner.diviner.ai; 2 | 3 | import com.openai.client.OpenAIClient; 4 | import com.openai.client.okhttp.OpenAIOkHttpClient; 5 | import com.openai.core.JsonField; 6 | import com.openai.core.http.StreamResponse; 7 | import com.openai.credential.BearerTokenCredential; 8 | import com.openai.models.*; 9 | 10 | /** 11 | * @author Coaixy 12 | * @createTime 2025-01-23 13 | * @packageName fun.diviner.diviner.util 14 | **/ 15 | 16 | public class AIRequestUtil { 17 | public static ReasoningResponse getAIResponse(String userPrompt, AIModel model) { 18 | StringBuilder content = new StringBuilder(); 19 | StringBuilder reasoning_content = new StringBuilder(); 20 | OpenAIOkHttpClient.Builder clientBuilder = OpenAIOkHttpClient.builder(); 21 | clientBuilder 22 | .baseUrl(model.getBaseApi()) 23 | .credential(BearerTokenCredential.create( 24 | model.getKey() 25 | )); 26 | OpenAIClient client = clientBuilder.build(); 27 | ChatCompletionCreateParams params = ChatCompletionCreateParams.builder() 28 | .addMessage(ChatCompletionMessageParam.ofChatCompletionUserMessageParam( 29 | ChatCompletionUserMessageParam.builder() 30 | .content(ChatCompletionUserMessageParam.Content.ofTextContent(userPrompt)) 31 | .build())) 32 | .model(model.getModelName()) 33 | .build(); 34 | StreamResponse chatCompletion = client.chat().completions().createStreaming(params); 35 | chatCompletion.stream().forEach(chunk -> { 36 | ChatCompletionChunk.Choice choice = chunk.choices().get(0); 37 | JsonField delta = choice._delta(); 38 | String tempContent = ""; 39 | if (delta.asObject().isPresent()){ 40 | tempContent = delta.asObject().get().get("content").toString(); 41 | }else{ 42 | tempContent = choice.delta().content().get(); 43 | } 44 | if (tempContent != null) content.append(tempContent); 45 | if (model == AIModel.DEEPSEEK_REPONSER){ 46 | String tempReasoningContent = delta.asObject().get().get("reasoning_content").toString(); 47 | if (tempReasoningContent != null) reasoning_content.append(tempReasoningContent); 48 | } 49 | }); 50 | 51 | return new ReasoningResponse( 52 | formatStr(content.toString()), 53 | formatStr(reasoning_content.toString()) 54 | ); 55 | } 56 | 57 | private static String formatStr(String str) { 58 | return str.replaceAll("null", "").replaceAll("\\*", "").replaceAll("#", ""); 59 | } 60 | } -------------------------------------------------------------------------------- /src/main/java/fun/diviner/aidiviner/diviner/ai/ReasoningResponse.java: -------------------------------------------------------------------------------- 1 | package fun.diviner.aidiviner.diviner.ai; 2 | 3 | import lombok.Getter; 4 | 5 | /** 6 | * @author Coaixy 7 | * @createTime 2025-01-23 8 | * @packageName fun.diviner.diviner.Ai 9 | **/ 10 | 11 | @Getter 12 | public class ReasoningResponse { 13 | private String content; 14 | private String reasoningContent; 15 | 16 | ReasoningResponse(String content, String reasoningContent) { 17 | this.content = content; 18 | this.reasoningContent = reasoningContent; 19 | } 20 | } -------------------------------------------------------------------------------- /src/main/java/fun/diviner/aidiviner/diviner/bazi/BaZiSetting.java: -------------------------------------------------------------------------------- 1 | package fun.diviner.aidiviner.diviner.bazi; 2 | 3 | import java.util.Calendar; 4 | import java.util.Date; 5 | 6 | import lombok.Data; 7 | 8 | /** 9 | * 八字-设置 10 | * 11 | * @author 善待 12 | */ 13 | @Data 14 | public class BaZiSetting { 15 | 16 | /** 17 | * 姓名 18 | */ 19 | private String name; 20 | 21 | /** 22 | * 占事 23 | */ 24 | private String occupy; 25 | 26 | /** 27 | * 性别(0:女。1:男) 28 | */ 29 | private int sex; 30 | 31 | /** 32 | * 日期 33 | */ 34 | private Date date; 35 | 36 | /** 37 | * 日期类型(0:公历。1:农历) 38 | */ 39 | private int dateType; 40 | 41 | /** 42 | * 地区 43 | */ 44 | private String address; 45 | 46 | /** 47 | * 闰月(0:不使用闰月。1:使用闰月) 48 | */ 49 | private int leapMonth; 50 | 51 | /** 52 | * 起运流派(0:按天数和时辰数计算:3天1年、1天4个月、1时辰10天。1:按分钟数计算:4320分=1年、360分=1月、12分=1天、1分=2小时) 53 | */ 54 | private int qiYunLiuPai; 55 | 56 | /** 57 | * 年干支设置(0:以正月初一作为新年的开始。1:以立春当天作为新年的开始。2:以立春交接的时刻作为新年的开始) 58 | */ 59 | private int yearGanZhiSet; 60 | 61 | /** 62 | * 月干支设置(0:以节交接当天起算。1:以节交接时刻起算) 63 | */ 64 | private int monthGanZhiSet; 65 | 66 | /** 67 | * 日干支设置(0:晚子时日柱按明天。1:晚子时日柱按当天) 68 | */ 69 | private int dayGanZhiSet; 70 | 71 | /** 72 | * 时干支设置(0:支持早子时和晚子时) 73 | */ 74 | private int hourGanZhiSet; 75 | 76 | /** 77 | * 人元司令分野类型(0:子平真诠法决。1:渊海子平法决。2:星平会海法决。3:三命通会法决。4:神峰通考法决。5:万育吾之法决) 78 | */ 79 | private int renYuan; 80 | 81 | //**************************************************************************************************************************************************** 82 | 83 | /** 84 | * 初始化设置 85 | */ 86 | public BaZiSetting() { 87 | 88 | initialize(); // 设置默认初始化数据 89 | 90 | } 91 | 92 | /** 93 | * 使用公历日期初始化 94 | * 95 | * @param date 公历日期 96 | */ 97 | public BaZiSetting(Date date) { 98 | 99 | initialize(); // 设置默认初始化数据 100 | 101 | this.date = date; // 日期 102 | 103 | } 104 | 105 | /** 106 | * 使用日期、日期类型初始化 107 | * 108 | * @param date 日期 109 | * @param dateType 日期类型(0:公历。1:农历) 110 | */ 111 | public BaZiSetting(Date date, int dateType) { 112 | 113 | initialize(); // 设置默认初始化数据 114 | 115 | this.date = date; // 日期 116 | this.dateType = dateType; // 日期类型(0:公历。1:农历) 117 | 118 | } 119 | 120 | /** 121 | * 使用公历年月日时分秒初始化 122 | * 123 | * @param year 年(1~9999) 124 | * @param month 月(1~12) 125 | * @param day 日 126 | * @param hour 时(0~24) 127 | * @param minute 分(0~60) 128 | * @param second 秒(0~60) 129 | */ 130 | public BaZiSetting(int year, int month, int day, int hour, int minute, int second) { 131 | 132 | initialize(); // 设置默认初始化数据 133 | 134 | Calendar c = Calendar.getInstance(); 135 | c.set(year, month - 1, day, hour, minute, second); 136 | this.date = c.getTime(); 137 | 138 | } 139 | 140 | /** 141 | * 设置默认初始化数据 142 | */ 143 | private void initialize() { 144 | 145 | this.name = null; // 姓名(默认→ 空) 146 | this.occupy = null; // 占事(默认→ 空) 147 | this.sex = 1; // 性别(默认→ 男) 148 | this.date = new Date(); // 日期(默认→ 当前时刻) 149 | this.dateType = 0; // 日期类型(默认→ 公历) 150 | this.address = null; // 地区(默认→ 空) 151 | this.leapMonth = 0; // 闰月(默认→ 不使用闰月) 152 | this.qiYunLiuPai = 0; // 起运流派(默认→ 按天数和时辰数计算:3天1年、1天4个月、1时辰10天) 153 | this.yearGanZhiSet = 1; // 年干支设置(默认→ 以立春当天作为新年的开始) 154 | this.monthGanZhiSet = 1; // 月干支设置(默认→ 以节交接时刻起算) 155 | this.dayGanZhiSet = 0; // 日干支设置,同子时流派(默认→ 晚子时日柱按当天) 156 | this.hourGanZhiSet = 0; // 时干支设置(默认→ 支持早子时和晚子时) 157 | this.renYuan = 0; // 人元司令分野类型(默认→ 子平真诠法决) 158 | 159 | } 160 | 161 | //---------------------------------------------------------------------------------------------------------------------------------------------------- 162 | 163 | /** 164 | * 性别设置 165 | * 166 | * @param sex 性别(0:女。1:男) 167 | */ 168 | public void setSex(int sex) { 169 | boolean boo = (sex == 0 || sex == 1); 170 | this.sex = boo ? sex : 1; 171 | } 172 | 173 | /** 174 | * 日期设置 175 | * 176 | * @param date 日期 177 | */ 178 | public void setDate(Date date) { 179 | this.date = (null == date ? new Date() : date); 180 | } 181 | 182 | /** 183 | * 日期类型设置 184 | * 185 | * @param dateType 日期类型(0:公历。1:农历) 186 | */ 187 | public void setDateType(int dateType) { 188 | boolean boo = (dateType == 0 || dateType == 1); 189 | this.dateType = boo ? dateType : 0; 190 | } 191 | 192 | /** 193 | * 闰月设置 194 | * 195 | * @param leapMonth 闰月(0:不使用闰月。1:使用闰月) 196 | */ 197 | public void setLeapMonth(int leapMonth) { 198 | boolean boo = (leapMonth == 0 || leapMonth == 1); 199 | this.leapMonth = boo ? leapMonth : 0; 200 | } 201 | 202 | /** 203 | * 起运流派设置 204 | * 205 | * @param qiYunLiuPai 起运流派(0:按天数和时辰数计算:3天1年、1天4个月、1时辰10天。1:按分钟数计算:4320分=1年、360分=1月、12分=1天、1分=2小时) 206 | */ 207 | public void setQiYunLiuPai(int qiYunLiuPai) { 208 | boolean boo = (qiYunLiuPai == 0 || qiYunLiuPai == 1); 209 | this.qiYunLiuPai = boo ? qiYunLiuPai : 0; 210 | } 211 | 212 | /** 213 | * 年干支设置 214 | * 215 | * @param yearGanZhiSet 年干支设置(0:以正月初一作为新年的开始。1:以立春当天作为新年的开始。2:以立春交接的时刻作为新年的开始) 216 | */ 217 | public void setYearGanZhiSet(int yearGanZhiSet) { 218 | boolean boo = (yearGanZhiSet == 0 || yearGanZhiSet == 1 || yearGanZhiSet == 2); 219 | this.yearGanZhiSet = boo ? yearGanZhiSet : 1; 220 | } 221 | 222 | /** 223 | * 月干支设置 224 | * 225 | * @param monthGanZhiSet 月干支设置(0:以节交接当天起算。1:以节交接时刻起算) 226 | */ 227 | public void setMonthGanZhiSet(int monthGanZhiSet) { 228 | boolean boo = (monthGanZhiSet == 0 || monthGanZhiSet == 1); 229 | this.monthGanZhiSet = boo ? monthGanZhiSet : 1; 230 | } 231 | 232 | /** 233 | * 日干支设置 234 | * 235 | * @param dayGanZhiSet 日干支设置(0:晚子时日干支算当天。1:晚子时日干支算明天) 236 | */ 237 | public void setDayGanZhiSet(int dayGanZhiSet) { 238 | boolean boo = (dayGanZhiSet == 0 || dayGanZhiSet == 1); 239 | this.dayGanZhiSet = boo ? dayGanZhiSet : 0; 240 | } 241 | 242 | /** 243 | * 人元司令分野类型 244 | * 245 | * @param renYuan 人元司令分野类型(0:子平真诠法决。1:渊海子平法决。2:星平会海法决。3:三命通会法决。4:神峰通考法决。5:万育吾之法决) 246 | */ 247 | public void setRenYuan(int renYuan) { 248 | boolean boo = (renYuan == 0 || renYuan == 1 || renYuan == 2 || renYuan == 3 || renYuan == 4 || renYuan == 5); 249 | this.renYuan = boo ? renYuan : 0; 250 | } 251 | 252 | 253 | } 254 | -------------------------------------------------------------------------------- /src/main/java/fun/diviner/aidiviner/diviner/bazi/BaZiUtil.java: -------------------------------------------------------------------------------- 1 | package fun.diviner.aidiviner.diviner.bazi; 2 | 3 | import java.util.*; 4 | 5 | import com.nlf.calendar.Lunar; 6 | import com.nlf.calendar.Solar; 7 | 8 | /** 9 | * 八字-工具 10 | * 11 | * @author 善待 12 | */ 13 | public class BaZiUtil { 14 | 15 | /** 16 | * 判断日期类型设置,返回公历日期、农历日期 17 | * 18 | * @param setting 八字-设置 19 | * @return 公历日期、农历日期 20 | */ 21 | public static Map isDateType(BaZiSetting setting) { 22 | 23 | // 1、初始化日期 24 | Solar solar = new Solar(); // 初始化公历日期 25 | Lunar lunar = new Lunar(); // 初始化农历日期 26 | 27 | // 2、获取设置数据 28 | Date date = setting.getDate(); // 日期 29 | int dateType = setting.getDateType(); // 日期类型 30 | 31 | // 3、按公历日期计算 32 | if (dateType == 0) { 33 | // 3.1、通过日期初始化 34 | solar = new Solar(date); // 公历日期 35 | lunar = solar.getLunar(); // 农历日期 36 | } 37 | 38 | // 4、按农历日期计算 39 | if (dateType == 1) { 40 | // 4.1、通过日期获取年月日时分秒 41 | Calendar c = Calendar.getInstance(); 42 | c.setTime(date); 43 | int year = c.get(Calendar.YEAR); // 年 44 | // 4.2、判断是否按闰月计算 45 | int month = (setting.getLeapMonth() == 1 ? -(c.get(Calendar.MONTH) + 1) : c.get(Calendar.MONTH) + 1); // 月 46 | int day = c.get(Calendar.DATE); // 日 47 | int hour = c.get(Calendar.HOUR_OF_DAY); // 时 48 | int minute = c.get(Calendar.MINUTE); // 分 49 | int second = c.get(Calendar.SECOND); // 秒 50 | // 4.3、通过农历年月日时初始化 51 | try { 52 | lunar = new Lunar(year, month, day, hour, minute, second); // 农历日期 53 | solar = lunar.getSolar(); // 公历日期 54 | } catch (IllegalArgumentException e) { 55 | throw new IllegalArgumentException(e.getMessage()); 56 | } 57 | } 58 | 59 | // 5、添加公历日期、农历日期并返回 60 | Map map = new HashMap<>(); 61 | map.put("solar", solar); // 公历日期 62 | map.put("lunar", lunar); // 农历日期 63 | return map; 64 | 65 | } 66 | 67 | /** 68 | * 判断干支设置,返回干支 69 | * 70 | * @param setting 八字-设置 71 | * @param lunar 农历日期 72 | * @return 干支 73 | */ 74 | public static Map> isGanZhi(BaZiSetting setting, Lunar lunar) { 75 | 76 | List list; 77 | Map> map = new HashMap<>(); 78 | 79 | // 年干支设置(0:以正月初一作为新年的开始。1:以立春当天作为新年的开始。2:以立春交接的时刻作为新年的开始) 80 | int yearGanZhiSet = setting.getYearGanZhiSet(); 81 | // 月干支设置(0:以节交接当天起算。1:以节交接时刻起算) 82 | int monthGanZhiSet = setting.getMonthGanZhiSet(); 83 | // 日干支设置(0:晚子时日干支算当天。1:晚子时日干支算明天) 84 | int dayGanZhiSet = setting.getDayGanZhiSet(); 85 | // 时干支设置(0:支持早子时和晚子时) 86 | int hourGanZhiSet = setting.getHourGanZhiSet(); 87 | 88 | // 1、判断年干支设置 89 | if (yearGanZhiSet == 0) { 90 | // 1.1、以正月初一作为新年的开始 91 | list = Arrays.asList(lunar.getYearGan(), lunar.getYearZhi(), lunar.getYearInGanZhi()); 92 | } else if (yearGanZhiSet == 1) { 93 | // 1.2、以立春当天作为新年的开始 94 | list = Arrays.asList(lunar.getYearGanByLiChun(), lunar.getYearZhiByLiChun(), lunar.getYearInGanZhiByLiChun()); 95 | } else if (yearGanZhiSet == 2) { 96 | // 1.3、以立春交接的时刻作为新年的开始 97 | list = Arrays.asList(lunar.getYearGanExact(), lunar.getYearZhiExact(), lunar.getYearInGanZhiExact()); 98 | } else { 99 | // 1.4、默认→ 以正月初一作为新年的开始 100 | list = Arrays.asList(lunar.getYearGan(), lunar.getYearZhi(), lunar.getYearInGanZhi()); 101 | } 102 | map.put("yearGanZhi", list); 103 | 104 | // 2、判断月干支设置 105 | if (monthGanZhiSet == 0) { 106 | // 2.1、以节交接当天起算 107 | list = Arrays.asList(lunar.getMonthGan(), lunar.getMonthZhi(), lunar.getMonthInGanZhi()); 108 | } else if (monthGanZhiSet == 1) { 109 | // 2.2、以节交接时刻起算 110 | list = Arrays.asList(lunar.getMonthGanExact(), lunar.getMonthZhiExact(), lunar.getMonthInGanZhiExact()); 111 | } else { 112 | // 2.3、默认→ 以节交接当天起算 113 | list = Arrays.asList(lunar.getMonthGan(), lunar.getMonthZhi(), lunar.getMonthInGanZhi()); 114 | } 115 | map.put("monthGanZhi", list); 116 | 117 | // 3、判断日干支设置 118 | if (dayGanZhiSet == 0) { 119 | // 3.1、晚子时日干支算明天 120 | list = Arrays.asList(lunar.getDayGanExact(), lunar.getDayZhiExact(), lunar.getDayInGanZhiExact()); 121 | } else if (dayGanZhiSet == 1) { 122 | // 3.2、晚子时日干支算当天 123 | list = Arrays.asList(lunar.getDayGanExact2(), lunar.getDayZhiExact2(), lunar.getDayInGanZhiExact2()); 124 | } else { 125 | // 3.3、默认→ 晚子时日干支算明天 126 | list = Arrays.asList(lunar.getDayGanExact(), lunar.getDayZhiExact(), lunar.getDayInGanZhiExact()); 127 | } 128 | map.put("dayGanZhi", list); 129 | 130 | // 4、判断日干支设置 131 | if (hourGanZhiSet == 0) { 132 | // 4.1、支持早子时和晚子时 133 | list = Arrays.asList(lunar.getTimeGan(), lunar.getTimeZhi(), lunar.getTimeInGanZhi()); 134 | } else { 135 | // 4.2、默认→ 支持早子时和晚子时 136 | list = Arrays.asList(lunar.getTimeGan(), lunar.getTimeZhi(), lunar.getTimeInGanZhi()); 137 | } 138 | map.put("hourGanZhi", list); 139 | 140 | // 5、返回干支 141 | return map; 142 | 143 | } 144 | 145 | 146 | } 147 | -------------------------------------------------------------------------------- /src/main/java/fun/diviner/aidiviner/diviner/bazi/shensha/BaZiShenShaUtil.java: -------------------------------------------------------------------------------- 1 | package fun.diviner.aidiviner.diviner.bazi.shensha; 2 | 3 | import java.util.ArrayList; 4 | import java.util.HashMap; 5 | import java.util.List; 6 | import java.util.Map; 7 | 8 | import lombok.Data; 9 | 10 | import fun.diviner.aidiviner.diviner.bazi.BaZiMap; 11 | import fun.diviner.aidiviner.diviner.util.CommonUtil; 12 | 13 | /** 14 | * 八字-神煞工具 15 | * 16 | * @author 善待 17 | */ 18 | @Data 19 | public class BaZiShenShaUtil { 20 | 21 | /** 22 | * 年干支 23 | */ 24 | private String yearGanZhi; 25 | /** 26 | * 月干支 27 | */ 28 | private String monthGanZhi; 29 | /** 30 | * 日干支 31 | */ 32 | private String dayGanZhi; 33 | /** 34 | * 时干支 35 | */ 36 | private String hourGanZhi; 37 | 38 | /** 39 | * 年干 40 | */ 41 | private String yearGan; 42 | /** 43 | * 月干 44 | */ 45 | private String monthGan; 46 | /** 47 | * 日干 48 | */ 49 | private String dayGan; 50 | /** 51 | * 时干 52 | */ 53 | private String hourGan; 54 | 55 | /** 56 | * 年支 57 | */ 58 | private String yearZhi; 59 | /** 60 | * 月支 61 | */ 62 | private String monthZhi; 63 | /** 64 | * 日支 65 | */ 66 | private String dayZhi; 67 | /** 68 | * 时支 69 | */ 70 | private String hourZhi; 71 | 72 | /** 73 | * 年干支纳音五行 74 | */ 75 | private String yearGanZhiNaYinWuXing; 76 | /** 77 | * 季节 78 | */ 79 | private String season; 80 | /** 81 | * 性别 82 | */ 83 | private String sex; 84 | 85 | /** 86 | * 年干支神煞 87 | */ 88 | private List yearGanZhiShenSha = new ArrayList<>(); 89 | /** 90 | * 月干支神煞 91 | */ 92 | private List monthGanZhiShenSha = new ArrayList<>(); 93 | /** 94 | * 日干支神煞 95 | */ 96 | private List dayGanZhiShenSha = new ArrayList<>(); 97 | /** 98 | * 时干支神煞 99 | */ 100 | private List hourGanZhiShenSha = new ArrayList<>(); 101 | 102 | /** 103 | * 四柱神煞 104 | */ 105 | Map> siZhuShenSha; 106 | 107 | //**************************************************************************************************************************************************** 108 | 109 | /** 110 | * 初始化常用神煞 111 | * 112 | * @param baZi 八字 113 | * @param yearGanZhiNaYinWuXing 年干支纳音五行 114 | * @param season 季节 115 | * @param sex 性别(男。女) 116 | */ 117 | public BaZiShenShaUtil(List baZi, String yearGanZhiNaYinWuXing, String season, String sex) { 118 | 119 | if (baZi.size() == 4) { 120 | this.yearGanZhi = baZi.get(0); // 年干支 121 | this.yearGan = baZi.get(0).substring(0, 1); // 年干 122 | this.yearZhi = baZi.get(0).substring(1, 2); // 年支 123 | this.monthGanZhi = baZi.get(1); // 月干支 124 | this.monthGan = baZi.get(1).substring(0, 1); // 月干 125 | this.monthZhi = baZi.get(1).substring(1, 2); // 月支 126 | this.dayGanZhi = baZi.get(2); // 日干支 127 | this.dayGan = baZi.get(2).substring(0, 1); // 日干 128 | this.dayZhi = baZi.get(2).substring(1, 2); // 日支 129 | this.hourGanZhi = baZi.get(3); // 时干支 130 | this.hourGan = baZi.get(3).substring(0, 1); // 时干 131 | this.hourZhi = baZi.get(3).substring(1, 2); // 时支 132 | } 133 | 134 | this.yearGanZhiNaYinWuXing = yearGanZhiNaYinWuXing; // 年干支纳音五行 135 | this.season = season; // 季节 136 | this.sex = sex; // 性别 137 | 138 | changYongShenSha(); // ★ 计算常用神煞 139 | 140 | } 141 | 142 | //==================================================================================================================================================== 143 | 144 | /** 145 | * ★ 计算常用神煞 146 | */ 147 | public void changYongShenSha() { 148 | 149 | // 1、计算数据 150 | taiJiGuiRen(); // 计算太极贵人【1】 151 | tianYiGuiRen(); // 计算天乙贵人【1】 152 | fuXingGuiRen(); // 计算福星贵人【1】 153 | wenChangGuiRen(); // 计算文昌贵人【1】 154 | tianChuGuiRen(); // 计算天厨贵人【1】 155 | yueDeGuiRen(); // 计算月德贵人【3】 156 | deXiuGuiRen(); // 计算德秀贵人【3】 157 | tianDeGuiRen(); // 计算天德贵人【4】 158 | shiEDaBai(); // 计算十恶大败【0】 159 | yinChaYangCuo(); // 计算阴差阳错【0】 160 | siFeiRi(); // 计算四废日【0】 161 | liuXiuRi(); // 计算六秀日【0】 162 | shiLingRi(); // 计算十灵日【0】 163 | kuiGangRi(); // 计算魁罡日【0】 164 | baZhuanRi(); // 计算八专日【0】 165 | jiuChouRi(); // 计算九丑日【0】 166 | siFeiRi(); // 计算四废日【0】 167 | guLuanSha(); // 计算孤鸾煞【0】 168 | hongYanSha(); // 计算红艳煞【1】 169 | gouJiaoSha(); // 计算勾绞煞【1】 170 | tongZiSha(); // 计算童子煞【7】 171 | huaGai(); // 计算华盖【6】 172 | guoYin(); // 计算国印【1】 173 | jiYu(); // 计算金舆【1】 174 | yangRen(); // 计算羊刃【1】 175 | feiRen(); // 计算飞刃【1】 176 | liuXia(); // 计算流霞【1】 177 | luShen(); // 计算禄神【1】 178 | yiMa(); // 计算驿马【1】 179 | jieSha(); // 计算劫煞【1】 180 | jiangXing(); // 计算将星【1】 181 | taoHua(); // 计算桃花【1】 182 | wangShen(); // 计算亡神【1】 183 | diaoKe(); // 计算吊客【1】 184 | piMa(); // 计算披麻【1】 185 | tianXi(); // 计算天喜【1】 186 | hongLuan(); // 计算红鸾【1】 187 | sangMen(); // 计算丧门【1】 188 | zaiSha(); // 计算灾煞【1】 189 | guChen(); // 计算孤辰【1】 190 | suGua(); // 计算寡宿 【1】 191 | yuanChen(); // 计算元辰【1】 192 | xueRen(); // 计算血刃【1】 193 | tianYi(); // 计算天医【1】 194 | ciGuan(); // 计算学堂【1】 195 | xueTang(); // 计算学堂【1】 196 | tianShe(); // 计算天赦【2】 197 | tianZhuan(); // 计算天转【2】 198 | diZhuan(); // 计算地转【2】 199 | gongLu(); // 计算拱禄【5】 200 | 201 | // 2、删除重复数据 202 | this.yearGanZhiShenSha = CommonUtil.removeDuplicates(getYearGanZhiShenSha()); // 年干支神煞 203 | this.monthGanZhiShenSha = CommonUtil.removeDuplicates(getMonthGanZhiShenSha()); // 月干支神煞 204 | this.dayGanZhiShenSha = CommonUtil.removeDuplicates(getDayGanZhiShenSha()); // 日干支神煞 205 | this.hourGanZhiShenSha = CommonUtil.removeDuplicates(getHourGanZhiShenSha()); // 时干支神煞 206 | 207 | } 208 | 209 | //---------------------------------------------------------------------------------------------------------------------------------------------------- 210 | 211 | /** 212 | * 计算四废日【0】 213 | */ 214 | private void siFeiRi() { 215 | 216 | Map map = BaZiShenShaMap.SI_FEI_RI; 217 | this.dayGanZhiShenSha.add(map.get(getSeason() + getDayGanZhi())); 218 | 219 | } 220 | 221 | /** 222 | * 计算十恶大败【0】 223 | */ 224 | private void shiEDaBai() { 225 | 226 | addShenSha(BaZiShenShaMap.SHI_E_DA_BAI, "十恶大败"); 227 | 228 | } 229 | 230 | /** 231 | * 计算阴差阳错【2】 232 | */ 233 | private void yinChaYangCuo() { 234 | 235 | addShenSha(BaZiShenShaMap.YIN_CHA_YANG_CUO, "阴差阳错"); 236 | 237 | } 238 | 239 | /** 240 | * 计算六秀日【2】 241 | */ 242 | private void liuXiuRi() { 243 | 244 | addShenSha(BaZiShenShaMap.LIU_XIU_RI, "六秀日"); 245 | 246 | } 247 | 248 | /** 249 | * 计算十灵日【2】 250 | */ 251 | private void shiLingRi() { 252 | 253 | addShenSha(BaZiShenShaMap.SHI_LING_RI, "十灵日"); 254 | 255 | } 256 | 257 | /** 258 | * 计算魁罡日【2】 259 | */ 260 | private void kuiGangRi() { 261 | 262 | addShenSha(BaZiShenShaMap.KUI_GANG_RI, "魁罡日"); 263 | 264 | } 265 | 266 | /** 267 | * 计算八专日【2】 268 | */ 269 | private void baZhuanRi() { 270 | 271 | addShenSha(BaZiShenShaMap.BA_ZHUAN_RI, "八专日"); 272 | 273 | } 274 | 275 | /** 276 | * 计算九丑日【2】 277 | */ 278 | private void jiuChouRi() { 279 | 280 | addShenSha(BaZiShenShaMap.JIU_CHOU_RI, "九丑日"); 281 | 282 | } 283 | 284 | /** 285 | * 计算孤鸾煞【2】 286 | */ 287 | private void guLuanSha() { 288 | 289 | addShenSha(BaZiShenShaMap.GU_LUAN_SHA, "孤鸾煞"); 290 | 291 | } 292 | 293 | //---------------------------------------------------------------------------------------------------------------------------------------------------- 294 | 295 | /** 296 | * 计算太极贵人【1】 297 | */ 298 | private void taiJiGuiRen() { 299 | 300 | Map map = BaZiShenShaMap.TAI_JI_GUI_REN; 301 | addSiZhuShenSha1(map, getYearGan(), getDayGan()); 302 | 303 | } 304 | 305 | /** 306 | * 计算天乙贵人【1】 307 | */ 308 | private void tianYiGuiRen() { 309 | 310 | Map map = BaZiShenShaMap.TIAN_YI_GUI_REN; 311 | addSiZhuShenSha1(map, getYearGan(), getDayGan()); 312 | 313 | } 314 | 315 | /** 316 | * 计算福星贵人【1】 317 | */ 318 | private void fuXingGuiRen() { 319 | 320 | Map map = BaZiShenShaMap.FU_XING_GUI_REN; 321 | addSiZhuShenSha1(map, getYearGan(), getDayGan()); 322 | 323 | } 324 | 325 | /** 326 | * 计算文昌贵人【1】 327 | */ 328 | private void wenChangGuiRen() { 329 | 330 | Map map = BaZiShenShaMap.WEN_CHANG_GUI_REN; 331 | addSiZhuShenSha1(map, getYearGan(), getDayGan()); 332 | 333 | } 334 | 335 | /** 336 | * 计算天厨贵人【1】 337 | */ 338 | private void tianChuGuiRen() { 339 | 340 | Map map = BaZiShenShaMap.TIAN_CHU_GUI_REN; 341 | addSiZhuShenSha1(map, getYearGan(), getDayGan()); 342 | 343 | } 344 | 345 | /** 346 | * 计算国印【1】 347 | */ 348 | private void guoYin() { 349 | 350 | Map map = BaZiShenShaMap.GUO_YIN; 351 | addSiZhuShenSha1(map, getYearGan(), getDayGan()); 352 | 353 | } 354 | 355 | /** 356 | * 计算金舆【1】 357 | */ 358 | private void jiYu() { 359 | 360 | Map map = BaZiShenShaMap.JIN_YU; 361 | addSiZhuShenSha1(map, getYearGan(), getDayGan()); 362 | 363 | } 364 | 365 | /** 366 | * 计算红艳煞【1】 367 | */ 368 | private void hongYanSha() { 369 | 370 | Map map = BaZiShenShaMap.HONG_YAN_SHA; 371 | addSiZhuShenSha1(map, "", getDayGan()); 372 | 373 | } 374 | 375 | /** 376 | * 计算羊刃【1】 377 | */ 378 | private void yangRen() { 379 | 380 | Map map = BaZiShenShaMap.YANG_REN; 381 | addSiZhuShenSha1(map, "", getDayGan()); 382 | 383 | } 384 | 385 | /** 386 | * 计算飞刃【1】 387 | */ 388 | private void feiRen() { 389 | 390 | Map map = BaZiShenShaMap.FEI_REN; 391 | addSiZhuShenSha1(map, "", getDayGan()); 392 | 393 | } 394 | 395 | /** 396 | * 计算流霞【1】 397 | */ 398 | private void liuXia() { 399 | 400 | Map map = BaZiShenShaMap.LIU_XIA; 401 | addSiZhuShenSha1(map, "", getDayGan()); 402 | 403 | } 404 | 405 | /** 406 | * 计算禄神【1】 407 | */ 408 | private void luShen() { 409 | 410 | Map map = BaZiShenShaMap.LU_SHEN; 411 | addSiZhuShenSha1(map, "", getDayGan()); 412 | 413 | } 414 | 415 | /** 416 | * 计算驿马【1】 417 | */ 418 | private void yiMa() { 419 | 420 | Map map = BaZiShenShaMap.YI_MA; 421 | addSiZhuShenSha1(map, getYearZhi(), getDayZhi()); 422 | 423 | } 424 | 425 | /** 426 | * 计算劫煞【1】 427 | */ 428 | private void jieSha() { 429 | 430 | Map map = BaZiShenShaMap.JIE_SHA; 431 | addSiZhuShenSha1(map, getYearZhi(), getDayZhi()); 432 | 433 | } 434 | 435 | /** 436 | * 计算将星【1】 437 | */ 438 | private void jiangXing() { 439 | 440 | Map map = BaZiShenShaMap.JIANG_XING; 441 | addSiZhuShenSha1(map, getYearZhi(), getDayZhi()); 442 | 443 | } 444 | 445 | /** 446 | * 计算桃花【1】 447 | */ 448 | private void taoHua() { 449 | 450 | Map map = BaZiShenShaMap.TAO_HUA; 451 | addSiZhuShenSha1(map, getYearZhi(), getDayZhi()); 452 | 453 | } 454 | 455 | /** 456 | * 计算亡神【1】 457 | */ 458 | private void wangShen() { 459 | 460 | Map map = BaZiShenShaMap.WANG_SHEN; 461 | addSiZhuShenSha1(map, getYearZhi(), getDayZhi()); 462 | 463 | } 464 | 465 | /** 466 | * 计算吊客【1】 467 | */ 468 | private void diaoKe() { 469 | 470 | Map map = BaZiShenShaMap.DIAO_KE; 471 | addSiZhuShenSha1(map, getYearZhi(), getDayZhi()); 472 | 473 | } 474 | 475 | /** 476 | * 计算披麻【1】 477 | */ 478 | private void piMa() { 479 | 480 | Map map = BaZiShenShaMap.PI_MA; 481 | addSiZhuShenSha1(map, getYearZhi(), getDayZhi()); 482 | 483 | } 484 | 485 | /** 486 | * 计算天喜【1】 487 | */ 488 | private void tianXi() { 489 | 490 | Map map = BaZiShenShaMap.TIAN_XI; 491 | addSiZhuShenSha1(map, getYearZhi(), ""); 492 | 493 | } 494 | 495 | /** 496 | * 计算勾绞煞【1】 497 | */ 498 | private void gouJiaoSha() { 499 | 500 | Map map = BaZiShenShaMap.GOU_JIAO_SHA; 501 | addSiZhuShenSha1(map, getYearZhi(), ""); 502 | 503 | } 504 | 505 | /** 506 | * 计算红鸾【1】 507 | */ 508 | private void hongLuan() { 509 | 510 | Map map = BaZiShenShaMap.HONG_LUAN; 511 | addSiZhuShenSha1(map, getYearZhi(), ""); 512 | 513 | } 514 | 515 | /** 516 | * 计算丧门【1】 517 | */ 518 | private void sangMen() { 519 | 520 | Map map = BaZiShenShaMap.SANG_MEN; 521 | addSiZhuShenSha1(map, getYearZhi(), ""); 522 | 523 | } 524 | 525 | /** 526 | * 计算灾煞【1】 527 | */ 528 | private void zaiSha() { 529 | 530 | Map map = BaZiShenShaMap.ZAI_SHA; 531 | addSiZhuShenSha1(map, getYearZhi(), ""); 532 | 533 | } 534 | 535 | /** 536 | * 计算孤辰【1】 537 | */ 538 | private void guChen() { 539 | 540 | Map map = BaZiShenShaMap.GU_CHEN; 541 | addSiZhuShenSha1(map, getYearZhi(), ""); 542 | 543 | } 544 | 545 | /** 546 | * 计算寡宿【1】 547 | */ 548 | private void suGua() { 549 | 550 | Map map = BaZiShenShaMap.SU_GUA; 551 | addSiZhuShenSha1(map, getYearZhi(), ""); 552 | 553 | } 554 | 555 | /** 556 | * 计算元辰【1】 557 | */ 558 | private void yuanChen() { 559 | 560 | Map yuanChenYangNan = BaZiShenShaMap.YUAN_CHEN_YANG_NAN; // 元辰(阳男阴女) 561 | Map yuanChenYinNan = BaZiShenShaMap.YUAN_CHEN_YIN_NAN; // 元辰(阴男阳女) 562 | String yearGanYinYang = BaZiMap.GAN_YIN_YANG.get(getYearGan()); // 年干阴阳 563 | 564 | Map map = new HashMap<>(); 565 | 566 | if ("阳".equals(yearGanYinYang) && "男".equals(getSex())) { 567 | map = yuanChenYangNan; // 阳男阴女 568 | } else if ("阴".equals(yearGanYinYang) && "男".equals(getSex())) { 569 | map = yuanChenYinNan; // 阴男阳女 570 | } else if ("阳".equals(yearGanYinYang) && "女".equals(getSex())) { 571 | map = yuanChenYinNan; // 阴男阳女 572 | } else if ("阴".equals(yearGanYinYang) && "女".equals(getSex())) { 573 | map = yuanChenYangNan; // 阳男阴女 574 | } 575 | 576 | addSiZhuShenSha1(map, getYearZhi(), ""); 577 | 578 | } 579 | 580 | /** 581 | * 计算血刃【1】 582 | */ 583 | private void xueRen() { 584 | 585 | Map map = BaZiShenShaMap.XUE_REN; 586 | addSiZhuShenSha1(map, getMonthZhi(), ""); 587 | 588 | } 589 | 590 | /** 591 | * 计算天医【1】 592 | */ 593 | private void tianYi() { 594 | 595 | Map map = BaZiShenShaMap.TIAN_YI; 596 | addSiZhuShenSha1(map, getMonthZhi(), ""); 597 | 598 | } 599 | 600 | /** 601 | * 计算词馆【1】 602 | */ 603 | private void ciGuan() { 604 | 605 | Map map = BaZiShenShaMap.CI_GUAN_LU_MING; 606 | addSiZhuShenSha1(map, getYearGanZhiNaYinWuXing(), ""); 607 | 608 | } 609 | 610 | /** 611 | * 计算学堂【1】 612 | */ 613 | private void xueTang() { 614 | 615 | Map map = BaZiShenShaMap.XUE_TANG_LU_MING; 616 | addSiZhuShenSha1(map, getYearGanZhiNaYinWuXing(), ""); 617 | 618 | } 619 | 620 | /** 621 | * 计算天赦【2】 622 | */ 623 | private void tianShe() { 624 | 625 | Map map = BaZiShenShaMap.TIAN_SHE; 626 | addSiZhuShenSha2(map, getMonthZhi()); 627 | 628 | } 629 | 630 | /** 631 | * 计算天转【2】 632 | */ 633 | private void tianZhuan() { 634 | 635 | Map map = BaZiShenShaMap.TIAN_ZHUAN; 636 | addSiZhuShenSha2(map, getMonthZhi()); 637 | 638 | } 639 | 640 | /** 641 | * 计算地转【2】 642 | */ 643 | private void diZhuan() { 644 | 645 | Map map = BaZiShenShaMap.DI_ZHUAN; 646 | addSiZhuShenSha2(map, getMonthZhi()); 647 | 648 | } 649 | 650 | /** 651 | * 计算月德贵人【3】 652 | */ 653 | private void yueDeGuiRen() { 654 | 655 | Map map = BaZiShenShaMap.YUE_DE_GUI_REN; 656 | addSiZhuShenSha3(map, getMonthZhi()); 657 | 658 | } 659 | 660 | /** 661 | * 计算德秀贵人【3】 662 | */ 663 | private void deXiuGuiRen() { 664 | 665 | Map map = BaZiShenShaMap.DE_XIU_GUI_REN; 666 | addSiZhuShenSha3(map, getMonthZhi()); 667 | 668 | } 669 | 670 | /** 671 | * 计算天德贵人【4】 672 | */ 673 | private void tianDeGuiRen() { 674 | 675 | Map map = BaZiShenShaMap.TIAN_DE_GUI_REN; 676 | addSiZhuShenSha4(map, getMonthZhi()); 677 | 678 | } 679 | 680 | /** 681 | * 计算拱禄【5】 682 | */ 683 | private void gongLu() { 684 | 685 | Map map = BaZiShenShaMap.GONG_LU; 686 | addSiZhuShenSha5(map, getDayGanZhi(), getHourGanZhi()); 687 | 688 | } 689 | 690 | /** 691 | * 计算华盖【6】 692 | */ 693 | private void huaGai() { 694 | 695 | Map map = BaZiShenShaMap.HUA_GAI; 696 | addSiZhuShenSha6(map, getYearZhi(), getDayZhi()); 697 | 698 | } 699 | 700 | /** 701 | * 计算童子煞【7】 702 | */ 703 | private void tongZiSha() { 704 | 705 | Map map = BaZiShenShaMap.TONG_ZI_SHA; 706 | addSiZhuShenSha7(map, getSeason(), getYearGanZhiNaYinWuXing()); 707 | 708 | } 709 | 710 | //---------------------------------------------------------------------------------------------------------------------------------------------------- 711 | 712 | /** 713 | * 添加神煞【0】 714 | * 715 | * @param strs 常用神煞常量 716 | * @param shenShaName 神煞名称 717 | */ 718 | private void addShenSha(String[] strs, String shenShaName) { 719 | 720 | // 判断日支,若匹配则添加日柱神煞 721 | for (String key : strs) { 722 | if (getDayGanZhi().equals(key)) this.dayGanZhiShenSha.add(shenShaName); 723 | } 724 | 725 | } 726 | 727 | /** 728 | * 添加神煞【1】 729 | * 730 | * @param map 常用神煞常量 731 | * @param ganZhi1 天干 或 地支 或 干支 或 年柱纳音五行 732 | * @param ganZhi2 天干 或 地支 或 干支 或 年柱纳音五行 733 | */ 734 | private void addSiZhuShenSha1(Map map, String ganZhi1, String ganZhi2) { 735 | 736 | this.yearGanZhiShenSha.add(map.get(ganZhi1 + getYearZhi())); 737 | this.monthGanZhiShenSha.add(map.get(ganZhi1 + getMonthZhi())); 738 | this.dayGanZhiShenSha.add(map.get(ganZhi1 + getDayZhi())); 739 | this.hourGanZhiShenSha.add(map.get(ganZhi1 + getHourZhi())); 740 | this.yearGanZhiShenSha.add(map.get(ganZhi2 + getYearZhi())); 741 | this.monthGanZhiShenSha.add(map.get(ganZhi2 + getMonthZhi())); 742 | this.dayGanZhiShenSha.add(map.get(ganZhi2 + getDayZhi())); 743 | this.hourGanZhiShenSha.add(map.get(ganZhi2 + getHourZhi())); 744 | 745 | } 746 | 747 | /** 748 | * 添加神煞【2】 749 | * 750 | * @param map 常用神煞常量 751 | * @param ganZhi1 天干 或 地支 或 干支 或 年柱纳音五行 752 | */ 753 | private void addSiZhuShenSha2(Map map, String ganZhi1) { 754 | 755 | this.yearGanZhiShenSha.add(map.get(ganZhi1 + getYearGanZhi())); 756 | this.monthGanZhiShenSha.add(map.get(ganZhi1 + getMonthGanZhi())); 757 | this.dayGanZhiShenSha.add(map.get(ganZhi1 + getDayGanZhi())); 758 | this.hourGanZhiShenSha.add(map.get(ganZhi1 + getHourGanZhi())); 759 | 760 | } 761 | 762 | /** 763 | * 添加神煞【3】 764 | * 765 | * @param map 常用神煞常量 766 | * @param ganZhi1 天干 或 地支 或 干支 或 年柱纳音五行 767 | */ 768 | private void addSiZhuShenSha3(Map map, String ganZhi1) { 769 | 770 | this.yearGanZhiShenSha.add(map.get(ganZhi1 + getYearGan())); 771 | this.monthGanZhiShenSha.add(map.get(ganZhi1 + getMonthGan())); 772 | this.dayGanZhiShenSha.add(map.get(ganZhi1 + getDayGan())); 773 | this.hourGanZhiShenSha.add(map.get(ganZhi1 + getHourGan())); 774 | 775 | } 776 | 777 | /** 778 | * 添加神煞【4】 779 | * 780 | * @param map 常用神煞常量 781 | * @param ganZhi 天干 或 地支 或 干支 782 | */ 783 | private void addSiZhuShenSha4(Map map, String ganZhi) { 784 | 785 | this.yearGanZhiShenSha.add(map.get(ganZhi + getYearGan())); 786 | this.monthGanZhiShenSha.add(map.get(ganZhi + getMonthGan())); 787 | this.dayGanZhiShenSha.add(map.get(ganZhi + getDayGan())); 788 | this.hourGanZhiShenSha.add(map.get(ganZhi + getHourGan())); 789 | this.yearGanZhiShenSha.add(map.get(ganZhi + getYearZhi())); 790 | this.monthGanZhiShenSha.add(map.get(ganZhi + getMonthZhi())); 791 | this.dayGanZhiShenSha.add(map.get(ganZhi + getDayZhi())); 792 | this.hourGanZhiShenSha.add(map.get(ganZhi + getHourZhi())); 793 | 794 | } 795 | 796 | /** 797 | * 添加神煞【5】 798 | * 799 | * @param map 常用神煞常量 800 | * @param ganZhi1 天干 或 地支 或 干支 801 | * @param ganZhi2 天干 或 地支 或 干支 802 | */ 803 | private void addSiZhuShenSha5(Map map, String ganZhi1, String ganZhi2) { 804 | 805 | this.yearGanZhiShenSha.add(map.get(ganZhi1 + ganZhi2 + getYearZhi())); 806 | this.monthGanZhiShenSha.add(map.get(ganZhi1 + ganZhi2 + getMonthZhi())); 807 | this.dayGanZhiShenSha.add(map.get(ganZhi1 + ganZhi2 + getDayZhi())); 808 | this.hourGanZhiShenSha.add(map.get(ganZhi1 + ganZhi2 + getHourZhi())); 809 | 810 | } 811 | 812 | /** 813 | * 添加神煞【6】 814 | * 815 | * @param map 常用神煞常量 816 | * @param ganZhi1 天干 或 地支 或 干支 或 年柱纳音五行 817 | * @param ganZhi2 天干 或 地支 或 干支 或 年柱纳音五行 818 | */ 819 | private void addSiZhuShenSha6(Map map, String ganZhi1, String ganZhi2) { 820 | 821 | // this.yearGanZhiShenSha.add(map.get(ganZhi1 + getYearZhi())); 822 | this.monthGanZhiShenSha.add(map.get(ganZhi1 + getMonthZhi())); 823 | this.dayGanZhiShenSha.add(map.get(ganZhi1 + getDayZhi())); 824 | this.hourGanZhiShenSha.add(map.get(ganZhi1 + getHourZhi())); 825 | this.yearGanZhiShenSha.add(map.get(ganZhi2 + getYearZhi())); 826 | this.monthGanZhiShenSha.add(map.get(ganZhi2 + getMonthZhi())); 827 | // this.dayGanZhiShenSha.add(map.get(ganZhi2 + getDayZhi())); 828 | this.hourGanZhiShenSha.add(map.get(ganZhi2 + getHourZhi())); 829 | 830 | } 831 | 832 | /** 833 | * 添加神煞【7】 834 | * 835 | * @param map 常用神煞常量 836 | * @param season 季节 837 | * @param yearGanZhiNaYinWuXing 年干支纳音五行 838 | */ 839 | private void addSiZhuShenSha7(Map map, String season, String yearGanZhiNaYinWuXing) { 840 | 841 | this.dayGanZhiShenSha.add(map.get(season + getDayZhi())); 842 | this.hourGanZhiShenSha.add(map.get(season + getHourZhi())); 843 | this.dayGanZhiShenSha.add(map.get(yearGanZhiNaYinWuXing + getDayZhi())); 844 | this.hourGanZhiShenSha.add(map.get(yearGanZhiNaYinWuXing + getHourZhi())); 845 | 846 | } 847 | 848 | 849 | } 850 | -------------------------------------------------------------------------------- /src/main/java/fun/diviner/aidiviner/diviner/liuyao/LiuYaoSetting.java: -------------------------------------------------------------------------------- 1 | package fun.diviner.aidiviner.diviner.liuyao; 2 | 3 | import java.util.Calendar; 4 | import java.util.Date; 5 | 6 | import lombok.Data; 7 | 8 | /** 9 | * 六爻-设置 10 | * 11 | * @author 善待 12 | */ 13 | @Data 14 | public class LiuYaoSetting { 15 | 16 | /** 17 | * 性别(0:女,1:男) 18 | */ 19 | private int sex; 20 | 21 | /** 22 | * 姓名 23 | */ 24 | private String name; 25 | 26 | /** 27 | * 占事 28 | */ 29 | private String occupy; 30 | 31 | /** 32 | * 日期 33 | */ 34 | private Date date; 35 | 36 | /** 37 | * 日期类型(0:公历,1:农历) 38 | */ 39 | private int dateType; 40 | 41 | /** 42 | * 地区 43 | */ 44 | private String address; 45 | 46 | /** 47 | * 闰月(0:不使用闰月。1:使用闰月) 48 | */ 49 | private int leapMonth; 50 | 51 | /** 52 | * 起卦模式(0:日期。1:自动。2:手动) 53 | */ 54 | private int qiGuaMode; 55 | 56 | /** 57 | * 上爻(0:—(2正1背)。1:- -(1正2背)。2:— ○(0正3背)。3:- - ×(3正0背)) 58 | */ 59 | private int liuYao; 60 | 61 | /** 62 | * 五爻(0:—(2正1背)。1:- -(1正2背)。2:— ○(0正3背)。3:- - ×(3正0背)) 63 | */ 64 | private int wuYao; 65 | 66 | /** 67 | * 四爻(0:—(2正1背)。1:- -(1正2背)。2:— ○(0正3背)。3:- - ×(3正0背)) 68 | */ 69 | private int siYao; 70 | 71 | /** 72 | * 三爻(0:—(2正1背)。1:- -(1正2背)。2:— ○(0正3背)。3:- - ×(3正0背)) 73 | */ 74 | private int sanYao; 75 | 76 | /** 77 | * 二爻(0:—(2正1背)。1:- -(1正2背)。2:— ○(0正3背)。3:- - ×(3正0背)) 78 | */ 79 | private int erYao; 80 | 81 | /** 82 | * 初爻(0:—(2正1背)。1:- -(1正2背)。2:— ○(0正3背)。3:- - ×(3正0背)) 83 | */ 84 | private int yiYao; 85 | 86 | /** 87 | * 年干支设置(0:以正月初一作为新年的开始。1:以立春当天作为新年的开始。2:以立春交接的时刻作为新年的开始) 88 | */ 89 | private int yearGanZhiSet; 90 | 91 | /** 92 | * 月干支设置(0:以节交接当天起算。1:以节交接时刻起算) 93 | */ 94 | private int monthGanZhiSet; 95 | 96 | /** 97 | * 日干支设置(0:晚子时日干支算当天。1:晚子时日干支算明天) 98 | */ 99 | private int dayGanZhiSet; 100 | 101 | /** 102 | * 时干支设置(0:支持早子时和晚子时) 103 | */ 104 | private int hourGanZhiSet; 105 | 106 | //------------------------------------------------------------------------------------------------------------------------------------ 107 | 108 | /** 109 | * 初始化设置 110 | */ 111 | public LiuYaoSetting() { 112 | 113 | initialize(); // 设置默认初始化数据 114 | 115 | } 116 | 117 | /** 118 | * 使用公历日期初始化 119 | * 120 | * @param date 公历日期 121 | */ 122 | public LiuYaoSetting(Date date) { 123 | 124 | initialize(); // 设置默认初始化数据 125 | 126 | this.date = date; // 日期 127 | 128 | } 129 | 130 | /** 131 | * 使用日期初始化 132 | * 133 | * @param date 公历日期 134 | * @param dateType 日期类型(0:公历。1:农历) 135 | */ 136 | public LiuYaoSetting(Date date, int dateType) { 137 | 138 | initialize(); // 设置默认初始化数据 139 | 140 | this.date = date; // 日期 141 | this.dateType = dateType; // 日期类型(0:公历。1:农历) 142 | 143 | } 144 | 145 | /** 146 | * 使用公历年月日时分秒初始化 147 | * 148 | * @param year 公历年(0~9999) 149 | * @param month 公历月(1~12) 150 | * @param day 公历日 151 | * @param hour 公历时(0~24) 152 | * @param minute 公历分(0~24) 153 | * @param second 公历秒(0~24) 154 | */ 155 | public LiuYaoSetting(int year, int month, int day, int hour, int minute, int second) { 156 | 157 | initialize(); // 设置默认初始化数据 158 | 159 | month -= 1; 160 | Calendar c = Calendar.getInstance(); 161 | c.set(year, month, day, hour, minute, second); 162 | this.date = c.getTime(); // 日期 163 | 164 | } 165 | 166 | /** 167 | * 使用年月日时分秒、日期类型初始化 168 | * 169 | * @param year 年 170 | * @param month 月 171 | * @param day 日 172 | * @param hour 时 173 | * @param minute 分 174 | * @param second 秒 175 | * @param dateType 日期类型(0:公历。1:农历) 176 | */ 177 | public LiuYaoSetting(int year, int month, int day, int hour, int minute, int second, int dateType) { 178 | 179 | initialize(); // 设置默认初始化数据 180 | 181 | month -= 1; 182 | Calendar c = Calendar.getInstance(); 183 | c.set(year, month, day, hour, minute, second); 184 | this.date = c.getTime(); // 日期 185 | this.dateType = dateType; // 日期类型(0:公历。1:农历) 186 | 187 | } 188 | 189 | /** 190 | * 设置默认初始化数据 191 | */ 192 | private void initialize() { 193 | 194 | this.sex = 1; // 性别(默认→ 男) 195 | this.name = null; // 姓名(默认→ 空) 196 | this.occupy = null; // 占事(默认→ 空) 197 | this.date = new Date(); // 日期(默认→ 当前时刻) 198 | this.dateType = 0; // 日期类型(默认→ 公历) 199 | this.address = null; // 地区(默认→ 空) 200 | this.leapMonth = 0; // 闰月(默认→ 不使用闰月) 201 | this.qiGuaMode = 0; // 起卦模式(默认→ 日期) 202 | this.liuYao = 0; // 上爻(默认→ 2正1背) 203 | this.wuYao = 0; // 五爻(默认→ 2正1背) 204 | this.siYao = 0; // 四爻(默认→ 2正1背) 205 | this.sanYao = 0; // 三爻(默认→ 2正1背) 206 | this.erYao = 0; // 二爻(默认→ 2正1背) 207 | this.yiYao = 0; // 初爻(默认→ 2正1背) 208 | this.yearGanZhiSet = 1; // 年干支设置(默认→ 以立春当天作为新年的开始) 209 | this.monthGanZhiSet = 1; // 月干支设置(默认→ 以节交接时刻起算) 210 | this.dayGanZhiSet = 0; // 日干支设置(默认→ 晚子时日干支算明天) 211 | this.hourGanZhiSet = 0; // 时干支设置(默认→ 支持早子时和晚子时) 212 | 213 | } 214 | 215 | //---------------------------------------------------------------------------------------------------------------------------------------------------- 216 | 217 | /** 218 | * 性别设置 219 | * 220 | * @param sex 性别(0:女。1:男) 221 | */ 222 | public void setSex(int sex) { 223 | boolean boo = (sex == 0 || sex == 1); 224 | this.sex = boo ? sex : 1; 225 | } 226 | 227 | /** 228 | * 日期设置 229 | * 230 | * @param date 日期 231 | */ 232 | public void setDate(Date date) { 233 | this.date = (null == date ? new Date() : date); 234 | } 235 | 236 | /** 237 | * 日期类型设置 238 | * 239 | * @param dateType 日期类型(0:公历。1:农历) 240 | */ 241 | public void setDateType(int dateType) { 242 | boolean boo = (dateType == 0 || dateType == 1); 243 | this.dateType = boo ? dateType : 0; 244 | } 245 | 246 | /** 247 | * 闰月设置 248 | * 249 | * @param leapMonth 闰月(0:不使用闰月。1:使用闰月) 250 | */ 251 | public void setLeapMonth(int leapMonth) { 252 | boolean boo = (leapMonth == 0 || leapMonth == 1); 253 | this.leapMonth = boo ? leapMonth : 0; 254 | } 255 | 256 | /** 257 | * 起卦模式设置 258 | * 259 | * @param qiGuaMode 起卦模式(0:日期。1:自动。2:手动) 260 | */ 261 | public void setQiGuaMode(int qiGuaMode) { 262 | boolean boo = (qiGuaMode == 0 || qiGuaMode == 1 || qiGuaMode == 2); 263 | this.qiGuaMode = boo ? qiGuaMode : 0; 264 | } 265 | 266 | /** 267 | * 上爻设置 268 | * 269 | * @param liuYao 上爻(0:—(2正1背)。1:- -(1正2背)。2:— ○(0正3背)。3:- - ×(3正0背)) 270 | */ 271 | public void setLiuYao(int liuYao) { 272 | boolean boo = (liuYao == 0 || liuYao == 1 || liuYao == 2 || liuYao == 3); 273 | this.liuYao = boo ? liuYao : 0; 274 | } 275 | 276 | /** 277 | * 五爻设置 278 | * 279 | * @param wuYao 五爻(0:—(2正1背)。1:- -(1正2背)。2:— ○(0正3背)。3:- - ×(3正0背)) 280 | */ 281 | public void setWuYao(int wuYao) { 282 | boolean boo = (wuYao == 0 || wuYao == 1 || wuYao == 2 || wuYao == 3); 283 | this.wuYao = boo ? wuYao : 0; 284 | } 285 | 286 | /** 287 | * 四爻设置 288 | * 289 | * @param siYao 四爻(0:—(2正1背)。1:- -(1正2背)。2:— ○(0正3背)。3:- - ×(3正0背)) 290 | */ 291 | public void setSiYao(int siYao) { 292 | boolean boo = (siYao == 0 || siYao == 1 || siYao == 2 || siYao == 3); 293 | this.siYao = boo ? siYao : 0; 294 | } 295 | 296 | /** 297 | * 三爻设置 298 | * 299 | * @param sanYao 三爻(0:—(2正1背)。1:- -(1正2背)。2:— ○(0正3背)。3:- - ×(3正0背)) 300 | */ 301 | public void setSanYao(int sanYao) { 302 | boolean boo = (sanYao == 0 || sanYao == 1 || sanYao == 2 || sanYao == 3); 303 | this.sanYao = boo ? sanYao : 0; 304 | } 305 | 306 | /** 307 | * 二爻设置 308 | * 309 | * @param erYao 二爻(0:—(2正1背)。1:- -(1正2背)。2:— ○(0正3背)。3:- - ×(3正0背)) 310 | */ 311 | public void setErYao(int erYao) { 312 | boolean boo = (erYao == 0 || erYao == 1 || erYao == 2 || erYao == 3); 313 | this.erYao = boo ? erYao : 0; 314 | } 315 | 316 | /** 317 | * 初爻设置 318 | * 319 | * @param yiYao 初爻(0:—(2正1背)。1:- -(1正2背)。2:— ○(0正3背)。3:- - ×(3正0背)) 320 | */ 321 | public void setYiYao(int yiYao) { 322 | boolean boo = (yiYao == 0 || yiYao == 1 || yiYao == 2 || yiYao == 3); 323 | this.yiYao = boo ? yiYao : 0; 324 | } 325 | 326 | /** 327 | * 年干支设置 328 | * 329 | * @param yearGanZhiSet 年干支设置(0:以正月初一作为新年的开始。1:以立春当天作为新年的开始。2:以立春交接的时刻作为新年的开始) 330 | */ 331 | public void setYearGanZhiSet(int yearGanZhiSet) { 332 | boolean boo = (yearGanZhiSet == 0 || yearGanZhiSet == 1); 333 | this.yearGanZhiSet = boo ? yearGanZhiSet : 1; 334 | } 335 | 336 | /** 337 | * 月干支设置 338 | * 339 | * @param monthGanZhiSet 月干支设置(0:以节交接当天起算。1:以节交接时刻起算) 340 | */ 341 | public void setMonthGanZhiSet(int monthGanZhiSet) { 342 | boolean boo = (monthGanZhiSet == 0 || monthGanZhiSet == 1); 343 | this.monthGanZhiSet = boo ? monthGanZhiSet : 1; 344 | } 345 | 346 | /** 347 | * 日干支设置 348 | * 349 | * @param dayGanZhiSet 日干支设置(0:晚子时日干支算当天。1:晚子时日干支算明天) 350 | */ 351 | public void setDayGanZhiSet(int dayGanZhiSet) { 352 | boolean boo = (dayGanZhiSet == 0 || dayGanZhiSet == 1); 353 | this.dayGanZhiSet = boo ? dayGanZhiSet : 0; 354 | } 355 | 356 | 357 | } 358 | -------------------------------------------------------------------------------- /src/main/java/fun/diviner/aidiviner/diviner/liuyao/LiuYaoUtil.java: -------------------------------------------------------------------------------- 1 | package fun.diviner.aidiviner.diviner.liuyao; 2 | 3 | import java.util.*; 4 | 5 | import com.nlf.calendar.Lunar; 6 | import com.nlf.calendar.Solar; 7 | 8 | import fun.diviner.aidiviner.diviner.util.CommonUtil; 9 | 10 | /** 11 | * 六爻-工具 12 | * 13 | * @author KTYkty 14 | */ 15 | public class LiuYaoUtil { 16 | 17 | /** 18 | * 判断日期类型设置,返回公历日期、农历日期 19 | * 20 | * @param setting 六爻-设置 21 | * @return 公历日期、农历日期 22 | */ 23 | public static Map isDateType(LiuYaoSetting setting) { 24 | 25 | // 1、初始化日期 26 | Solar solar = new Solar(); // 初始化公历日期 27 | Lunar lunar = new Lunar(); // 初始化农历日期 28 | 29 | // 2、获取设置数据 30 | Date date = setting.getDate(); // 日期 31 | int dateType = setting.getDateType(); // 日期类型 32 | 33 | // 3、按公历日期计算 34 | if (dateType == 0) { 35 | // 3.1、通过日期初始化 36 | solar = new Solar(date); // 公历日期 37 | lunar = solar.getLunar(); // 农历日期 38 | } 39 | 40 | // 4、按农历日期计算 41 | if (dateType == 1) { 42 | // 4.1、通过日期获取年月日时分秒 43 | Calendar c = Calendar.getInstance(); 44 | c.setTime(date); 45 | int year = c.get(Calendar.YEAR); // 年 46 | // 4.2、判断是否按闰月计算 47 | int month = (setting.getLeapMonth() == 1 ? -(c.get(Calendar.MONTH) + 1) : c.get(Calendar.MONTH) + 1); // 月 48 | int day = c.get(Calendar.DATE); // 日 49 | int hour = c.get(Calendar.HOUR_OF_DAY); // 时 50 | int minute = c.get(Calendar.MINUTE); // 分 51 | int second = c.get(Calendar.SECOND); // 秒 52 | // 4.3、通过农历年月日时初始化 53 | try { 54 | lunar = new Lunar(year, month, day, hour, minute, second); // 农历日期 55 | solar = lunar.getSolar(); // 公历日期 56 | } catch (IllegalArgumentException e) { 57 | throw new IllegalArgumentException(e.getMessage()); 58 | } 59 | } 60 | 61 | // 5、添加公历日期、农历日期并返回 62 | Map map = new HashMap<>(); 63 | map.put("solar", solar); // 公历日期 64 | map.put("lunar", lunar); // 农历日期 65 | return map; 66 | 67 | } 68 | 69 | /** 70 | * 判断干支设置,返回干支 71 | * 72 | * @param setting 六爻-设置 73 | * @param lunar 农历日期 74 | * @return 干支 75 | */ 76 | public static Map> isGanZhi(LiuYaoSetting setting, Lunar lunar) { 77 | 78 | List list; 79 | Map> map = new HashMap<>(); 80 | 81 | // 年干支设置(0:以正月初一作为新年的开始。1:以立春当天作为新年的开始。2:以立春交接的时刻作为新年的开始) 82 | int yearGanZhiSet = setting.getYearGanZhiSet(); 83 | // 月干支设置(0:以节交接当天起算。1:以节交接时刻起算) 84 | int monthGanZhiSet = setting.getMonthGanZhiSet(); 85 | // 日干支设置(0:晚子时日干支算当天。1:晚子时日干支算明天) 86 | int dayGanZhiSet = setting.getDayGanZhiSet(); 87 | // 时干支设置(0:支持早子时和晚子时) 88 | int hourGanZhiSet = setting.getHourGanZhiSet(); 89 | 90 | // 1、判断年干支设置 91 | if (yearGanZhiSet == 0) { 92 | // 1.1、以正月初一作为新年的开始 93 | list = Arrays.asList(lunar.getYearGan(), lunar.getYearZhi(), lunar.getYearInGanZhi()); 94 | } else if (yearGanZhiSet == 1) { 95 | // 1.2、以立春当天作为新年的开始 96 | list = Arrays.asList(lunar.getYearGanByLiChun(), lunar.getYearZhiByLiChun(), lunar.getYearInGanZhiByLiChun()); 97 | } else if (yearGanZhiSet == 2) { 98 | // 1.3、以立春交接的时刻作为新年的开始 99 | list = Arrays.asList(lunar.getYearGanExact(), lunar.getYearZhiExact(), lunar.getYearInGanZhiExact()); 100 | } else { 101 | // 1.4、默认→ 以正月初一作为新年的开始 102 | list = Arrays.asList(lunar.getYearGan(), lunar.getYearZhi(), lunar.getYearInGanZhi()); 103 | } 104 | map.put("yearGanZhi", list); 105 | 106 | // 2、判断月干支设置 107 | if (monthGanZhiSet == 0) { 108 | // 2.1、以节交接当天起算 109 | list = Arrays.asList(lunar.getMonthGan(), lunar.getMonthZhi(), lunar.getMonthInGanZhi()); 110 | } else if (monthGanZhiSet == 1) { 111 | // 2.2、以节交接时刻起算 112 | list = Arrays.asList(lunar.getMonthGanExact(), lunar.getMonthZhiExact(), lunar.getMonthInGanZhiExact()); 113 | } else { 114 | // 2.3、默认→ 以节交接当天起算 115 | list = Arrays.asList(lunar.getMonthGan(), lunar.getMonthZhi(), lunar.getMonthInGanZhi()); 116 | } 117 | map.put("monthGanZhi", list); 118 | 119 | // 3、判断日干支设置 120 | if (dayGanZhiSet == 0) { 121 | // 3.1、晚子时日干支算明天 122 | list = Arrays.asList(lunar.getDayGanExact(), lunar.getDayZhiExact(), lunar.getDayInGanZhiExact()); 123 | } else if (dayGanZhiSet == 1) { 124 | // 3.2、晚子时日干支算当天 125 | list = Arrays.asList(lunar.getDayGanExact2(), lunar.getDayZhiExact2(), lunar.getDayInGanZhiExact2()); 126 | } else { 127 | // 3.3、默认→ 晚子时日干支算明天 128 | list = Arrays.asList(lunar.getDayGanExact(), lunar.getDayZhiExact(), lunar.getDayInGanZhiExact()); 129 | } 130 | map.put("dayGanZhi", list); 131 | 132 | // 4、判断日干支设置 133 | if (hourGanZhiSet == 0) { 134 | // 4.1、支持早子时和晚子时 135 | list = Arrays.asList(lunar.getTimeGan(), lunar.getTimeZhi(), lunar.getTimeInGanZhi()); 136 | } else { 137 | // 4.2、默认→ 支持早子时和晚子时 138 | list = Arrays.asList(lunar.getTimeGan(), lunar.getTimeZhi(), lunar.getTimeInGanZhi()); 139 | } 140 | map.put("hourGanZhi", list); 141 | 142 | // 5、返回干支 143 | return map; 144 | 145 | } 146 | 147 | /** 148 | * 判断起卦模式并返回六爻爻象、六爻爻象标识、六爻爻象标识名称 149 | * 150 | * @param setting 六爻-设置 151 | * @return 六爻爻象、六爻爻象标识、六爻爻象标识名称 152 | */ 153 | public static List> isQiGuaMode(LiuYaoSetting setting) { 154 | 155 | /* 156 | 一、自动起卦:随机产生六爻进行起卦。 157 | 二、手动起卦:手动指定六爻进行起卦。 158 | */ 159 | 160 | List liuYaoYaoXiang = new ArrayList<>(); // 保存六爻爻象(如:[—, - -, - -, - -, - -, —]) 161 | List liuYaoYaoXiangMark = new ArrayList<>(); // 保存六爻爻象标识(如:[○, ×, , ×, , ]) 162 | List liuYaoYaoXiangMarkName = new ArrayList<>(); // 保存六爻爻象标识名称(如:[老阳, 老阴, 少阴, 老阴, 少阴, 少阳]) 163 | 164 | // 1、自动起卦模式 165 | if (setting.getQiGuaMode() == 1) { 166 | Map, List> map = LiuYaoMap.AUTO_RANDOM_YAO; // 【少阳、少阴、老阳、老阴】对应信息 167 | // 1.1、计算六爻(循环6次,分别对应:初爻(一爻)、二爻、三爻、四爻、五爻、上爻(六爻)) 168 | for (int i = 0; i < 6; i++) { 169 | // 随机产生0~1中的3个数字 170 | List randomList = CommonUtil.randomList(3, 1); 171 | // 保存六爻爻象(顺序:初爻(一爻)、二爻、三爻、四爻、五爻、上爻(六爻)) 172 | liuYaoYaoXiang.add(map.get(randomList).get(0)); 173 | // 保存六爻爻象标识(顺序:初爻(一爻)、二爻、三爻、四爻、五爻、上爻(六爻)) 174 | liuYaoYaoXiangMark.add(map.get(randomList).get(1)); 175 | // 保存六爻爻象标识名称(顺序:初爻(一爻)、二爻、三爻、四爻、五爻、上爻(六爻)) 176 | liuYaoYaoXiangMarkName.add(map.get(randomList).get(2)); 177 | } 178 | return Arrays.asList(liuYaoYaoXiang, liuYaoYaoXiangMark, liuYaoYaoXiangMarkName); 179 | } 180 | 181 | // 2、手动起卦模式 182 | if (setting.getQiGuaMode() == 2) { 183 | Map> map = LiuYaoMap.MANUAL_RANDOM_YAO; // 【少阳、少阴、老阳、老阴】对应信息 184 | // 2.1、封装六爻 185 | List packageList = CommonUtil.packageList(setting.getYiYao(), setting.getErYao(), setting.getSanYao(), setting.getSiYao(), setting.getWuYao(), setting.getLiuYao()); 186 | // 2.2、计算六爻【循环6次,分别对应:初爻(一爻)、二爻、三爻、四爻、五爻、上爻(六爻)】 187 | for (int i = 0; i < 6; i++) { 188 | // 保存六爻爻象(顺序:初爻(一爻)、二爻、三爻、四爻、五爻、上爻(六爻)) 189 | liuYaoYaoXiang.add(map.get(packageList.get(i)).get(0)); 190 | // 保存六爻爻象标识(顺序:初爻(一爻)、二爻、三爻、四爻、五爻、上爻(六爻)) 191 | liuYaoYaoXiangMark.add(map.get(packageList.get(i)).get(1)); 192 | // 保存六爻爻象标识名称(顺序:初爻(一爻)、二爻、三爻、四爻、五爻、上爻(六爻)) 193 | liuYaoYaoXiangMarkName.add(map.get(packageList.get(i)).get(2)); 194 | } 195 | return Arrays.asList(liuYaoYaoXiang, liuYaoYaoXiangMark, liuYaoYaoXiangMarkName); 196 | } 197 | 198 | return null; 199 | 200 | } 201 | 202 | 203 | } 204 | -------------------------------------------------------------------------------- /src/main/java/fun/diviner/aidiviner/diviner/meihua/MeiHuaSetting.java: -------------------------------------------------------------------------------- 1 | package fun.diviner.aidiviner.diviner.meihua; 2 | 3 | import java.util.Calendar; 4 | import java.util.Date; 5 | 6 | import lombok.Data; 7 | 8 | /** 9 | * 梅花易数-设置 10 | * 11 | * @author 善待 12 | */ 13 | @Data 14 | public class MeiHuaSetting { 15 | 16 | /** 17 | * 性别(0:女。1:男) 18 | */ 19 | private int sex; 20 | 21 | /** 22 | * 姓名 23 | */ 24 | private String name; 25 | 26 | /** 27 | * 占事 28 | */ 29 | private String occupy; 30 | 31 | /** 32 | * 日期 33 | */ 34 | private Date date; 35 | 36 | /** 37 | * 日期类型(0:公历。1:农历) 38 | */ 39 | private int dateType; 40 | 41 | /** 42 | * 地区 43 | */ 44 | private String address; 45 | 46 | /** 47 | * 闰月(0:不使用闰月。1:使用闰月) 48 | */ 49 | private int leapMonth; 50 | 51 | /** 52 | * 起卦模式(0:日期。1:数字。2:单数。3:双数) 53 | */ 54 | private int qiGuaMode; 55 | 56 | /** 57 | * 起卦数(起卦模式为[数字]时生效,三位数) 58 | */ 59 | private int qiGuaNumber; 60 | 61 | /** 62 | * 起卦数(起卦模式为[单数]时生效) 63 | */ 64 | private int qiGuaDanNumber; 65 | 66 | /** 67 | * 起卦双数1(起卦模式为[双数]时生效) 68 | */ 69 | private int qiGuaShuangNumber1; 70 | 71 | /** 72 | * 起卦双数2(起卦模式为[双数]时生效) 73 | */ 74 | private int qiGuaShuangNumber2; 75 | 76 | /** 77 | * 双数计算上下卦(0:双数求和计算上下卦。1:双数不求和计算上下卦) 78 | */ 79 | private int qiGuaShuangNumberInSx; 80 | 81 | /** 82 | * 双数计算动爻(0:双数求和计算动爻。1:双数求和加时辰数计算动爻) 83 | */ 84 | private int qiGuaShuangNumberInDong; 85 | 86 | /** 87 | * 年干支设置(0:以正月初一作为新年的开始。1:以立春当天作为新年的开始。2:以立春交接的时刻作为新年的开始) 88 | */ 89 | private int yearGanZhiSet; 90 | 91 | /** 92 | * 月干支设置(0:以节交接当天起算。1:以节交接时刻起算) 93 | */ 94 | private int monthGanZhiSet; 95 | 96 | /** 97 | * 日干支设置(0:晚子时日干支算当天。1:晚子时日干支算明天) 98 | */ 99 | private int dayGanZhiSet; 100 | 101 | /** 102 | * 时干支设置(0:支持早子时和晚子时) 103 | */ 104 | private int hourGanZhiSet; 105 | 106 | //**************************************************************************************************************************************************** 107 | 108 | /** 109 | * 初始化设置 110 | */ 111 | public MeiHuaSetting() { 112 | 113 | initialize(); // 设置默认初始化数据 114 | 115 | } 116 | 117 | /** 118 | * 使用公历日期初始化 119 | * 120 | * @param date 公历日期 121 | */ 122 | public MeiHuaSetting(Date date) { 123 | 124 | initialize(); // 设置默认初始化数据 125 | 126 | this.date = date; // 日期 127 | 128 | } 129 | 130 | /** 131 | * 使用日期初始化 132 | * 133 | * @param date 公历日期 134 | * @param dateType 日期类型(0:公历。1:农历) 135 | */ 136 | public MeiHuaSetting(Date date, int dateType) { 137 | 138 | initialize(); // 设置默认初始化数据 139 | 140 | this.date = date; // 日期 141 | this.dateType = dateType; // 日期类型(0:公历。1:农历) 142 | 143 | } 144 | 145 | /** 146 | * 使用公历年月日时分秒初始化 147 | * 148 | * @param year 公历年(0~9999) 149 | * @param month 公历月(1~12) 150 | * @param day 公历日 151 | * @param hour 公历时(0~24) 152 | * @param minute 公历分(0~24) 153 | * @param second 公历秒(0~24) 154 | */ 155 | public MeiHuaSetting(int year, int month, int day, int hour, int minute, int second) { 156 | 157 | initialize(); // 设置默认初始化数据 158 | 159 | month -= 1; 160 | Calendar c = Calendar.getInstance(); 161 | c.set(year, month, day, hour, minute, second); 162 | this.date = c.getTime(); // 日期 163 | 164 | } 165 | 166 | /** 167 | * 使用年月日时分秒、日期类型初始化 168 | * 169 | * @param year 年 170 | * @param month 月 171 | * @param day 日 172 | * @param hour 时 173 | * @param minute 分 174 | * @param second 秒 175 | * @param dateType 日期类型(0:公历。1:农历) 176 | */ 177 | public MeiHuaSetting(int year, int month, int day, int hour, int minute, int second, int dateType) { 178 | 179 | initialize(); // 设置默认初始化数据 180 | 181 | month -= 1; 182 | Calendar c = Calendar.getInstance(); 183 | c.set(year, month, day, hour, minute, second); 184 | this.date = c.getTime(); // 日期 185 | this.dateType = dateType; // 日期类型(0:公历。1:农历) 186 | 187 | } 188 | 189 | /** 190 | * 设置默认初始化数据 191 | */ 192 | private void initialize() { 193 | 194 | this.sex = 1; // 性别(默认→ 男) 195 | this.name = null; // 姓名(默认→ 空) 196 | this.occupy = null; // 占事(默认→ 空) 197 | this.date = new Date(); // 日期(默认→ 当前时刻) 198 | this.dateType = 0; // 日期类型(默认→ 公历) 199 | this.address = null; // 地区(默认→ 空) 200 | this.leapMonth = 0; // 闰月(默认→ 不使用闰月) 201 | this.qiGuaMode = 0; // 起卦模式(默认→ 日期) 202 | this.qiGuaNumber = 111; // 起卦数(默认→ 111) 203 | this.qiGuaDanNumber = 1111; // 起卦数(默认→ 1111) 204 | this.qiGuaShuangNumber1 = 1234; // 起卦双数1(默认→ 1234) 205 | this.qiGuaShuangNumber2 = 1234; // 起卦双数2(默认→ 1234) 206 | this.qiGuaShuangNumberInSx = 1; // 双数计算上下卦(默认→ 双数不求和计算上下卦) 207 | this.qiGuaShuangNumberInDong = 0; // 双数计算动爻(默认→ 双数求和计算动爻) 208 | this.yearGanZhiSet = 1; // 年干支设置(默认→ 以立春当天作为新年的开始) 209 | this.monthGanZhiSet = 1; // 月干支设置(默认→ 以节交接时刻起算) 210 | this.dayGanZhiSet = 0; // 日干支设置(默认→ 晚子时日干支算明天) 211 | this.hourGanZhiSet = 0; // 时干支设置(默认→ 支持早子时和晚子时) 212 | 213 | } 214 | 215 | //---------------------------------------------------------------------------------------------------------------------------------------------------- 216 | 217 | /** 218 | * 性别设置 219 | * 220 | * @param sex 性别(0:女。1:男) 221 | */ 222 | public void setSex(int sex) { 223 | boolean boo = (sex == 0 || sex == 1); 224 | this.sex = boo ? sex : 1; 225 | } 226 | 227 | /** 228 | * 日期设置 229 | * 230 | * @param date 日期 231 | */ 232 | public void setDate(Date date) { 233 | this.date = (null == date ? new Date() : date); 234 | } 235 | 236 | /** 237 | * 日期类型设置 238 | * 239 | * @param dateType 日期类型(0:公历。1:农历) 240 | */ 241 | public void setDateType(int dateType) { 242 | boolean boo = (dateType == 0 || dateType == 1); 243 | this.dateType = boo ? dateType : 0; 244 | } 245 | 246 | /** 247 | * 闰月设置 248 | * 249 | * @param leapMonth 闰月(0:不使用闰月。1:使用闰月) 250 | */ 251 | public void setLeapMonth(int leapMonth) { 252 | boolean boo = (leapMonth == 0 || leapMonth == 1); 253 | this.leapMonth = boo ? leapMonth : 0; 254 | } 255 | 256 | /** 257 | * 起卦模式设置 258 | * 259 | * @param qiGuaMode 起卦模式(0:日期。1:数字。2:单数。3:双数) 260 | */ 261 | public void setQiGuaMode(int qiGuaMode) { 262 | boolean boo = (qiGuaMode == 0 || qiGuaMode == 1 || qiGuaMode == 2 || qiGuaMode == 3); 263 | this.qiGuaMode = boo ? qiGuaMode : 0; 264 | } 265 | 266 | /** 267 | * 起卦数设置 268 | * 269 | * @param qiGuaNumber 起卦数(起卦模式为[数字]时生效,三位数) 270 | */ 271 | public void setQiGuaNumber(int qiGuaNumber) { 272 | boolean boo = (qiGuaNumber > 100 && qiGuaNumber < 999); 273 | this.qiGuaNumber = boo ? qiGuaNumber : 111; 274 | } 275 | 276 | /** 277 | * 起卦数设置 278 | * 279 | * @param qiGuaDanNumber 起卦数(起卦模式为[单数]时生效) 280 | */ 281 | public void setQiGuaDanNumber(int qiGuaDanNumber) { 282 | boolean boo = (qiGuaDanNumber > 0 && qiGuaDanNumber < 2147483647); 283 | this.qiGuaDanNumber = boo ? qiGuaDanNumber : 1111; 284 | } 285 | 286 | /** 287 | * 起卦双数1设置 288 | * 289 | * @param qiGuaShuangNumber1 起卦双数1(起卦模式为[双数]时生效) 290 | */ 291 | public void setQiGuaShuangNumber1(int qiGuaShuangNumber1) { 292 | boolean boo = (qiGuaShuangNumber1 > 0 && qiGuaShuangNumber1 < 2147483647); 293 | this.qiGuaShuangNumber1 = boo ? qiGuaShuangNumber1 : 1111; 294 | } 295 | 296 | /** 297 | * 起卦双数2设置 298 | * 299 | * @param qiGuaShuangNumber2 起卦双数2(起卦模式为[双数]时生效) 300 | */ 301 | public void setQiGuaShuangNumber2(int qiGuaShuangNumber2) { 302 | boolean boo = (qiGuaShuangNumber2 > 0 && qiGuaShuangNumber2 < 2147483647); 303 | this.qiGuaShuangNumber2 = boo ? qiGuaShuangNumber2 : 1111; 304 | } 305 | 306 | /** 307 | * 双数计算上下卦设置 308 | * 309 | * @param qiGuaShuangNumberInSx 双数计算上下卦(0:双数求和计算上下卦。1:双数不求和计算上下卦) 310 | */ 311 | public void setQiGuaShuangNumberInSx(int qiGuaShuangNumberInSx) { 312 | boolean boo = (qiGuaShuangNumberInSx == 0 || qiGuaShuangNumberInSx == 1); 313 | this.qiGuaShuangNumberInSx = boo ? qiGuaShuangNumberInSx : 1; 314 | this.qiGuaShuangNumberInSx = qiGuaShuangNumberInSx; 315 | } 316 | 317 | /** 318 | * 双数计算动爻设置 319 | * 320 | * @param qiGuaShuangNumberInDong 双数计算动爻(0:双数求和计算动爻。1:双数求和加时辰数计算动爻) 321 | */ 322 | public void setQiGuaShuangNumberInDong(int qiGuaShuangNumberInDong) { 323 | boolean boo = (qiGuaShuangNumberInDong == 0 || qiGuaShuangNumberInDong == 1); 324 | this.qiGuaShuangNumberInDong = boo ? qiGuaShuangNumberInDong : 0; 325 | } 326 | 327 | /** 328 | * 年干支设置 329 | * 330 | * @param yearGanZhiSet 年干支设置(0:以正月初一作为新年的开始。1:以立春当天作为新年的开始。2:以立春交接的时刻作为新年的开始) 331 | */ 332 | public void setYearGanZhiSet(int yearGanZhiSet) { 333 | boolean boo = (yearGanZhiSet == 0 || yearGanZhiSet == 1); 334 | this.yearGanZhiSet = boo ? yearGanZhiSet : 1; 335 | } 336 | 337 | /** 338 | * 月干支设置 339 | * 340 | * @param monthGanZhiSet 月干支设置(0:以节交接当天起算。1:以节交接时刻起算) 341 | */ 342 | public void setMonthGanZhiSet(int monthGanZhiSet) { 343 | boolean boo = (monthGanZhiSet == 0 || monthGanZhiSet == 1); 344 | this.monthGanZhiSet = boo ? monthGanZhiSet : 1; 345 | } 346 | 347 | /** 348 | * 日干支设置 349 | * 350 | * @param dayGanZhiSet 日干支设置(0:晚子时日干支算当天。1:晚子时日干支算明天) 351 | */ 352 | public void setDayGanZhiSet(int dayGanZhiSet) { 353 | boolean boo = (dayGanZhiSet == 0 || dayGanZhiSet == 1); 354 | this.dayGanZhiSet = boo ? dayGanZhiSet : 0; 355 | } 356 | 357 | 358 | } 359 | -------------------------------------------------------------------------------- /src/main/java/fun/diviner/aidiviner/diviner/meihua/MeiHuaUtil.java: -------------------------------------------------------------------------------- 1 | package fun.diviner.aidiviner.diviner.meihua; 2 | 3 | import java.util.*; 4 | 5 | import com.nlf.calendar.Lunar; 6 | import com.nlf.calendar.Solar; 7 | 8 | /** 9 | * 梅花易数-工具 10 | * 11 | * @author 善待 12 | */ 13 | public class MeiHuaUtil { 14 | 15 | /** 16 | * 判断日期类型设置,返回公历日期、农历日期 17 | * 18 | * @param setting 梅花易数-设置 19 | * @return 公历日期、农历日期 20 | */ 21 | public static Map isDateType(MeiHuaSetting setting) { 22 | 23 | // 1、初始化日期 24 | Solar solar = new Solar(); // 初始化公历日期 25 | Lunar lunar = new Lunar(); // 初始化农历日期 26 | 27 | // 2、获取设置数据 28 | Date date = setting.getDate(); // 日期 29 | int dateType = setting.getDateType(); // 日期类型 30 | 31 | // 3、按公历日期计算 32 | if (dateType == 0) { 33 | // 3.1、通过日期初始化 34 | solar = new Solar(date); // 公历日期 35 | lunar = solar.getLunar(); // 农历日期 36 | } 37 | 38 | // 4、按农历日期计算 39 | if (dateType == 1) { 40 | // 4.1、通过日期获取年月日时分秒 41 | Calendar c = Calendar.getInstance(); 42 | c.setTime(date); 43 | int year = c.get(Calendar.YEAR); // 年 44 | // 4.2、判断是否按闰月计算 45 | int month = (setting.getLeapMonth() == 1 ? -(c.get(Calendar.MONTH) + 1) : c.get(Calendar.MONTH) + 1); // 月 46 | int day = c.get(Calendar.DATE); // 日 47 | int hour = c.get(Calendar.HOUR_OF_DAY); // 时 48 | int minute = c.get(Calendar.MINUTE); // 分 49 | int second = c.get(Calendar.SECOND); // 秒 50 | // 4.3、通过农历年月日时初始化 51 | try { 52 | lunar = new Lunar(year, month, day, hour, minute, second); // 农历日期 53 | solar = lunar.getSolar(); // 公历日期 54 | } catch (IllegalArgumentException e) { 55 | throw new IllegalArgumentException(e.getMessage()); 56 | } 57 | } 58 | 59 | // 5、添加公历日期、农历日期并返回 60 | Map map = new HashMap<>(); 61 | map.put("solar", solar); // 公历日期 62 | map.put("lunar", lunar); // 农历日期 63 | return map; 64 | 65 | } 66 | 67 | /** 68 | * 判断干支设置,返回干支 69 | * 70 | * @param setting 梅花易数-设置 71 | * @param lunar 农历日期 72 | * @return 干支 73 | */ 74 | public static Map> isGanZhi(MeiHuaSetting setting, Lunar lunar) { 75 | 76 | List list; 77 | Map> map = new HashMap<>(); 78 | 79 | // 年干支设置(0:以正月初一作为新年的开始。1:以立春当天作为新年的开始。2:以立春交接的时刻作为新年的开始) 80 | int yearGanZhiSet = setting.getYearGanZhiSet(); 81 | // 月干支设置(0:以节交接当天起算。1:以节交接时刻起算) 82 | int monthGanZhiSet = setting.getMonthGanZhiSet(); 83 | // 日干支设置(0:晚子时日干支算当天。1:晚子时日干支算明天) 84 | int dayGanZhiSet = setting.getDayGanZhiSet(); 85 | // 时干支设置(0:支持早子时和晚子时) 86 | int hourGanZhiSet = setting.getHourGanZhiSet(); 87 | 88 | // 1、判断年干支设置 89 | if (yearGanZhiSet == 0) { 90 | // 1.1、以正月初一作为新年的开始 91 | list = Arrays.asList(lunar.getYearGan(), lunar.getYearZhi(), lunar.getYearInGanZhi()); 92 | } else if (yearGanZhiSet == 1) { 93 | // 1.2、以立春当天作为新年的开始 94 | list = Arrays.asList(lunar.getYearGanByLiChun(), lunar.getYearZhiByLiChun(), lunar.getYearInGanZhiByLiChun()); 95 | } else if (yearGanZhiSet == 2) { 96 | // 1.3、以立春交接的时刻作为新年的开始 97 | list = Arrays.asList(lunar.getYearGanExact(), lunar.getYearZhiExact(), lunar.getYearInGanZhiExact()); 98 | } else { 99 | // 1.4、默认→ 以正月初一作为新年的开始 100 | list = Arrays.asList(lunar.getYearGan(), lunar.getYearZhi(), lunar.getYearInGanZhi()); 101 | } 102 | map.put("yearGanZhi", list); 103 | 104 | // 2、判断月干支设置 105 | if (monthGanZhiSet == 0) { 106 | // 2.1、以节交接当天起算 107 | list = Arrays.asList(lunar.getMonthGan(), lunar.getMonthZhi(), lunar.getMonthInGanZhi()); 108 | } else if (monthGanZhiSet == 1) { 109 | // 2.2、以节交接时刻起算 110 | list = Arrays.asList(lunar.getMonthGanExact(), lunar.getMonthZhiExact(), lunar.getMonthInGanZhiExact()); 111 | } else { 112 | // 2.3、默认→ 以节交接当天起算 113 | list = Arrays.asList(lunar.getMonthGan(), lunar.getMonthZhi(), lunar.getMonthInGanZhi()); 114 | } 115 | map.put("monthGanZhi", list); 116 | 117 | // 3、判断日干支设置 118 | if (dayGanZhiSet == 0) { 119 | // 3.1、晚子时日干支算明天 120 | list = Arrays.asList(lunar.getDayGanExact(), lunar.getDayZhiExact(), lunar.getDayInGanZhiExact()); 121 | } else if (dayGanZhiSet == 1) { 122 | // 3.2、晚子时日干支算当天 123 | list = Arrays.asList(lunar.getDayGanExact2(), lunar.getDayZhiExact2(), lunar.getDayInGanZhiExact2()); 124 | } else { 125 | // 3.3、默认→ 晚子时日干支算明天 126 | list = Arrays.asList(lunar.getDayGanExact(), lunar.getDayZhiExact(), lunar.getDayInGanZhiExact()); 127 | } 128 | map.put("dayGanZhi", list); 129 | 130 | // 4、判断日干支设置 131 | if (hourGanZhiSet == 0) { 132 | // 4.1、支持早子时和晚子时 133 | list = Arrays.asList(lunar.getTimeGan(), lunar.getTimeZhi(), lunar.getTimeInGanZhi()); 134 | } else { 135 | // 4.2、默认→ 支持早子时和晚子时 136 | list = Arrays.asList(lunar.getTimeGan(), lunar.getTimeZhi(), lunar.getTimeInGanZhi()); 137 | } 138 | map.put("hourGanZhi", list); 139 | 140 | // 5、返回干支 141 | return map; 142 | 143 | } 144 | 145 | /** 146 | * 判断起卦模式并返回起卦数 147 | * 148 | * @param setting 梅花易数起卦-设置 149 | */ 150 | public static List isQiGuaMode(MeiHuaSetting setting) { 151 | 152 | /* 153 | 一、数字起卦法:取一个三位数,第一位数字作为上卦数,第二位数字作为下卦数,第一位数字作为动爻数。 154 | 155 | 二、单数起卦法:取一个数,前半部分的数字之和÷8取余数作为上卦数,后半部分的数字之和÷8取余数作为下卦数,全数之和÷6作为动爻数。 156 | 157 | 三、双数起卦法: 158 | 1、取第一个数字(和)÷8取余数作为上卦数; 159 | 2、取第二个数字(和)÷8取余数作为下卦数; 160 | 3、两个数字之和(+时辰数)÷6作为动爻数。 161 | */ 162 | 163 | List list = new ArrayList<>(); 164 | 165 | // 1、数字起卦模式 166 | if (setting.getQiGuaMode() == 1) { 167 | // 1.1、获取起卦数(起卦模式为[数字]时生效,三位数) 168 | String number = String.valueOf(setting.getQiGuaNumber()); 169 | int shangGuaNumber = Integer.parseInt(String.valueOf(number.charAt(0))); // 上卦数 170 | int xiaGuaNumber = Integer.parseInt(String.valueOf(number.charAt(1))); // 下卦数 171 | int dongYaoNumber = Integer.parseInt(String.valueOf(number.charAt(2))); // 动爻数 172 | list = shangXiaDongNumber(shangGuaNumber, xiaGuaNumber, dongYaoNumber); 173 | } 174 | 175 | // 2、单数起卦模式 176 | if (setting.getQiGuaMode() == 2) { 177 | // 2.1、起卦数(起卦模式为[单数]时生效) 178 | String number = String.valueOf(setting.getQiGuaDanNumber()); 179 | // 2.2、计算[上卦数、下卦数、动爻数](单数起卦方式调用) 180 | list = shangXiaDongNumber(number); 181 | } 182 | 183 | // 3、双数起卦模式 184 | if (setting.getQiGuaMode() == 3) { 185 | // 3.1、获取两个数字(起卦模式为[双数]时生效) 186 | String number1 = String.valueOf(setting.getQiGuaShuangNumber1()); 187 | String number2 = String.valueOf(setting.getQiGuaShuangNumber2()); 188 | // 3.2、计算[上卦数、下卦数、动爻数](双数起卦方式调用) 189 | list = shangXiaDongNumber(number1, number2, setting); 190 | } 191 | 192 | return list; 193 | 194 | } 195 | 196 | //------------------------------------------------------------------------------------------------------------------------------------ 197 | 198 | /** 199 | * 计算[上卦数、下卦数、动爻数](单数起卦法调用) 200 | * 201 | * @param number 数字 202 | * @return 上卦数、下卦数、动爻数 203 | */ 204 | private static List shangXiaDongNumber(String number) { 205 | 206 | int length = number.length(); // 数字位数 207 | 208 | // 1、计算前半段数字之和、后半段数字之和 209 | int number1Count = 0; // 前半段数字之和 210 | int number2Count = 0; // 后半段数字之和 211 | if (length > 1) { 212 | // 1.1、前半段数字取0~(总位数÷2)位,后半段数字取(总位数÷2)~最后一位 213 | String number1 = number.substring(0, length / 2); 214 | String number2 = number.substring(length / 2, length); 215 | for (int i = 0; i < number1.length(); i++) { 216 | number1Count += Integer.parseInt(number1.split("")[i]); 217 | } 218 | for (int i = 0; i < number2.length(); i++) { 219 | number2Count += Integer.parseInt(number2.split("")[i]); 220 | } 221 | } 222 | 223 | return shangXiaDongNumber2(number1Count, number2Count, 0); 224 | 225 | } 226 | 227 | /** 228 | * 计算[上卦数、下卦数、动爻数](双数起卦法调用) 229 | * 230 | * @param number1 数字一 231 | * @param number2 数字二 232 | * @param setting 梅花易数起卦-设置 233 | * @return 上卦数、下卦数、动爻数 234 | */ 235 | private static List shangXiaDongNumber(String number1, String number2, MeiHuaSetting setting) { 236 | 237 | int number1Count = Integer.parseInt(number1); // 数字一 238 | int number2Count = Integer.parseInt(number2); // 数字二 239 | 240 | // 1、双数求和计算上下卦 241 | if (setting.getQiGuaShuangNumberInSx() == 0) { 242 | number1Count = 0; 243 | number2Count = 0; 244 | // 1.1、计算第一个数字的数字之和 245 | for (int i = 0; i < number1.length(); i++) { 246 | number1Count += Integer.parseInt(number1.split("")[i]); 247 | } 248 | // 1.2、计算第二个数字的数字之和 249 | for (int i = 0; i < number2.length(); i++) { 250 | number2Count += Integer.parseInt(number2.split("")[i]); 251 | } 252 | } 253 | 254 | // 2、双数求和加时辰数计算动爻 255 | int hourNumber = number1Count + number2Count; 256 | if (setting.getQiGuaShuangNumberInDong() == 1) { 257 | // 获取时数 258 | Lunar lunar = new Lunar(setting.getDate()); 259 | String timeZhi = lunar.getTimeZhi(); // 获取'时地支' 260 | hourNumber += MeiHuaMap.DI_ZHI_SHU.get(timeZhi); // 获取'时地支'对应的数字并设置【时数】 261 | } 262 | 263 | return shangXiaDongNumber2(number1Count, number2Count, hourNumber); 264 | 265 | } 266 | 267 | /** 268 | * 通用方法:计算[上卦数、下卦数、动爻数] 269 | * 270 | * @param number1 数字一 271 | * @param number2 数字二 272 | * @param number3 数字三 273 | * @return 上卦数、下卦数、动爻数 274 | */ 275 | private static List shangXiaDongNumber(int number1, int number2, int number3) { 276 | 277 | // 1、计算上卦数 278 | int shangGuaNumber = (number1 % 8); 279 | shangGuaNumber = (shangGuaNumber == 0) ? 8 : shangGuaNumber; // 若除尽则统一用8来表示 280 | 281 | // 2、计算下卦数 282 | int xiaGuaNumber = (number2 % 8); 283 | xiaGuaNumber = (xiaGuaNumber == 0) ? 8 : xiaGuaNumber; // 若除尽则统一用8来表示 284 | 285 | // 3、计算动爻数 286 | int dongYaoNumber = (number3 % 6); 287 | dongYaoNumber = (dongYaoNumber == 0) ? 6 : dongYaoNumber; // 若除尽则统一用6来表示 288 | 289 | return Arrays.asList(shangGuaNumber, xiaGuaNumber, dongYaoNumber); 290 | 291 | } 292 | 293 | /** 294 | * 通用方法:计算[上卦数、下卦数、动爻数] 295 | * 296 | * @param number1 数字一 297 | * @param number2 数字二 298 | * @param hourNumber 时辰数 299 | * @return 上卦数、下卦数、动爻数 300 | */ 301 | private static List shangXiaDongNumber2(int number1, int number2, int hourNumber) { 302 | 303 | // 1、计算上卦数 304 | int shangGuaNumber = (number1 % 8); 305 | shangGuaNumber = (shangGuaNumber == 0) ? 8 : shangGuaNumber; // 若除尽则统一用8来表示 306 | 307 | // 2、计算下卦数 308 | int xiaGuaNumber = (number2 % 8); 309 | xiaGuaNumber = (xiaGuaNumber == 0) ? 8 : xiaGuaNumber; // 若除尽则统一用8来表示 310 | 311 | // 3、计算动爻数 312 | int dongYaoNumber = ((number1 + number2 + hourNumber) % 6); 313 | dongYaoNumber = (dongYaoNumber == 0) ? 6 : dongYaoNumber; // 若除尽则统一用6来表示 314 | 315 | return Arrays.asList(shangGuaNumber, xiaGuaNumber, dongYaoNumber); 316 | 317 | } 318 | 319 | 320 | } 321 | -------------------------------------------------------------------------------- /src/main/java/fun/diviner/aidiviner/diviner/type/BaZiArrangeItem.java: -------------------------------------------------------------------------------- 1 | package fun.diviner.aidiviner.diviner.type; 2 | 3 | import java.util.List; 4 | 5 | import lombok.Getter; 6 | 7 | /** 8 | * { name: '年柱', heavenlyStems: '甲', earthlyBranches: '子', hidden: ['癸'], deities: '偏印', godOfDestiny: '天乙贵人' }, 9 | */ 10 | @Getter 11 | public class BaZiArrangeItem { 12 | private String name; 13 | private String heavenlyStems; 14 | private String earthlyBranches; 15 | private List hidden; 16 | private String deities; 17 | private List fuxing; 18 | 19 | public BaZiArrangeItem(String name, String heavenlyStems, String earthlyBranches, List hidden, String deities, List fuxing) { 20 | this.name = name; 21 | this.heavenlyStems = heavenlyStems; 22 | this.earthlyBranches = earthlyBranches; 23 | this.hidden = hidden; 24 | this.deities = deities; 25 | this.fuxing = fuxing; 26 | } 27 | } -------------------------------------------------------------------------------- /src/main/java/fun/diviner/aidiviner/diviner/type/BaZiArrangeResponse.java: -------------------------------------------------------------------------------- 1 | package fun.diviner.aidiviner.diviner.type; 2 | 3 | import java.util.List; 4 | 5 | import lombok.Data; 6 | 7 | /** 8 | * @author Coaixy 9 | * @createTime 2024-11-09 10 | * @packageName fun.diviner.diviner 11 | **/ 12 | 13 | @Data 14 | public class BaZiArrangeResponse { 15 | private BaZiArrangeItem yearPillar; 16 | private BaZiArrangeItem monthPillar; 17 | private BaZiArrangeItem dayPillar; 18 | private BaZiArrangeItem hourPillar; 19 | private List baZiWuXingCount; 20 | private List baZiwuXingWangShuai; 21 | private String bodyIntensity; 22 | private String guZhong; 23 | private String guZhongPiZhu; 24 | private String dayZhuLunMing; 25 | private String yinYuan; 26 | private String wuXingFenXi; 27 | private List> dayun; 28 | private List> liuNian; 29 | } -------------------------------------------------------------------------------- /src/main/java/fun/diviner/aidiviner/diviner/type/LiuYaoArrangeResponse.java: -------------------------------------------------------------------------------- 1 | package fun.diviner.aidiviner.diviner.type; 2 | 3 | import java.util.List; 4 | 5 | import lombok.Data; 6 | 7 | /** 8 | * @author Coaixy 9 | * @createTime 2024-11-29 10 | * @packageName fun.diviner.diviner.type 11 | **/ 12 | 13 | @Data 14 | public class LiuYaoArrangeResponse { 15 | private List bazi; 16 | private List xunkong; 17 | private LiuYaoItem ben; 18 | private LiuYaoItem bian; 19 | private List dong; 20 | } -------------------------------------------------------------------------------- /src/main/java/fun/diviner/aidiviner/diviner/type/LiuYaoItem.java: -------------------------------------------------------------------------------- 1 | package fun.diviner.aidiviner.diviner.type; 2 | 3 | import java.util.List; 4 | 5 | import lombok.Data; 6 | 7 | /** 8 | * @author Coaixy 9 | * @createTime 2024-11-29 10 | * @packageName fun.diviner.diviner.type 11 | **/ 12 | 13 | @Data 14 | public class LiuYaoItem { 15 | private String name; 16 | private List yao; 17 | private List gan; 18 | private List wuxing; 19 | private List liuqin; 20 | private List liushou; 21 | private List shiying; 22 | } -------------------------------------------------------------------------------- /src/main/java/fun/diviner/aidiviner/diviner/type/MeiHuaArrangeResponse.java: -------------------------------------------------------------------------------- 1 | package fun.diviner.aidiviner.diviner.type; 2 | 3 | import java.util.List; 4 | 5 | import lombok.Data; 6 | 7 | /** 8 | * @author Coaixy 9 | * @createTime 2024-11-20 10 | * @packageName fun.diviner.diviner 11 | **/ 12 | 13 | @Data 14 | public class MeiHuaArrangeResponse { 15 | private List bazi; 16 | private MeiHuaGuaItem ben; 17 | private MeiHuaGuaItem hu; 18 | private MeiHuaGuaItem bian; 19 | private int dong; 20 | } -------------------------------------------------------------------------------- /src/main/java/fun/diviner/aidiviner/diviner/type/MeiHuaGuaItem.java: -------------------------------------------------------------------------------- 1 | package fun.diviner.aidiviner.diviner.type; 2 | 3 | import java.util.List; 4 | 5 | import lombok.Data; 6 | 7 | /** 8 | * @author Coaixy 9 | * @createTime 2024-11-20 10 | * @packageName fun.diviner.diviner 11 | **/ 12 | 13 | @Data 14 | public class MeiHuaGuaItem { 15 | private String name; 16 | private String guaci; 17 | private String shanggua; 18 | private String xiagua; 19 | private List yao; 20 | } -------------------------------------------------------------------------------- /src/main/java/fun/diviner/aidiviner/diviner/type/TarotResponse.java: -------------------------------------------------------------------------------- 1 | package fun.diviner.aidiviner.diviner.type; 2 | 3 | import java.util.List; 4 | 5 | import lombok.Data; 6 | 7 | import fun.diviner.aidiviner.entity.database.ToolTarotCard; 8 | 9 | @Data 10 | public class TarotResponse { 11 | public String question; 12 | public String spreadName; 13 | public List cardList; 14 | public List reverseList; 15 | public String answer; 16 | } -------------------------------------------------------------------------------- /src/main/java/fun/diviner/aidiviner/diviner/util/BaiduMapsUtil.java: -------------------------------------------------------------------------------- 1 | package fun.diviner.aidiviner.diviner.util; 2 | 3 | import java.io.BufferedReader; 4 | import java.io.InputStreamReader; 5 | import java.net.URL; 6 | import java.net.URLConnection; 7 | import java.nio.charset.StandardCharsets; 8 | import java.util.HashMap; 9 | import java.util.Map; 10 | 11 | import com.alibaba.fastjson.JSONObject; 12 | import org.apache.commons.lang3.StringUtils; 13 | 14 | /** 15 | * 百度地图定位工具 16 | * 17 | *

API地址:https://lbsyun.baidu.com/faq/api?title=webapi

18 | */ 19 | public class BaiduMapsUtil { 20 | 21 | /** 22 | * 开发者密钥 23 | */ 24 | private static final String ak = ""; // 密钥申请地址:https://lbsyun.baidu.com/apiconsole/key#/home 25 | 26 | //**************************************************************************************************************************************************** 27 | 28 | /** 29 | * 通过地区获取经纬度 30 | * 31 | * @param address 地区 32 | * @return 经纬度 33 | */ 34 | public static Map getLngAndLat(String address) { 35 | 36 | /* 接口文档地址:https://lbsyun.baidu.com/faq/api?title=webapi/guide/webservice-geocoding-base */ 37 | 38 | // 1、参数校验 39 | if (StringUtils.isBlank(ak)) throw new NullPointerException("⚠ 请填写开发者密钥"); 40 | if (StringUtils.isBlank(address)) throw new NullPointerException("⚠ 请填写地区"); 41 | 42 | // 2、发送URL请求 43 | String url = "https://api.map.baidu.com/geocoding/v3/?address=" + address + "&output=json&ak=" + ak; 44 | JSONObject data = sendUrl(url); 45 | 46 | // 3、获取数据 47 | Map map = new HashMap<>(); 48 | if (data.get("status").toString().equals("0")) { 49 | map.put("lng", data.getJSONObject("result").getJSONObject("location").getDouble("lng")); // 经度 50 | map.put("lat", data.getJSONObject("result").getJSONObject("location").getDouble("lat")); // 纬度 51 | } else { 52 | throw new NullPointerException("⚠ 定位异常"); 53 | } 54 | 55 | return map; 56 | 57 | } 58 | 59 | /** 60 | * 通过经纬度获取地区 61 | * 62 | * @param lng 经度 63 | * @param lat 纬度 64 | * @return 地区 65 | */ 66 | public static String getAddress(String lng, String lat) { 67 | 68 | /* 接口文档地址:https://lbsyun.baidu.com/faq/api?title=webapi/guide/webservice-geocoding-abroad-base */ 69 | 70 | // 1、参数校验 71 | if (StringUtils.isBlank(ak)) throw new NullPointerException("⚠ 请填写开发者密钥"); 72 | if (StringUtils.isBlank(lng) || StringUtils.isBlank(lat)) throw new NullPointerException("⚠ 请填完善经纬度"); 73 | 74 | // 2、发送URL请求 75 | String url = "https://api.map.baidu.com/reverse_geocoding/v3/?location=" + lat + "," + lng + "&output=json&coordtype=wgs84ll&extensions_poi=1&extensions_town=true&ak=" + ak; 76 | JSONObject data = sendUrl(url); 77 | 78 | // 3、获取数据 79 | String address; 80 | if (data.get("status").toString().equals("0")) { 81 | address = data.getJSONObject("result").getString("formatted_address"); // 标准的结构化地址 82 | } else { 83 | throw new NullPointerException("⚠ 定位异常"); 84 | } 85 | 86 | return address; 87 | 88 | } 89 | 90 | /** 91 | * 通过机器ip定位获取地区(若机器ip为空,则根据发送请求的机器ip定位) 92 | * 93 | * @param ip 机器ip(如:127.0.0.1) 94 | * @return 地区 95 | */ 96 | public static String getIpToAddress(String ip) { 97 | 98 | /* 接口文档地址:https://lbsyun.baidu.com/faq/api?title=webapi/ip-api-base */ 99 | 100 | // 1、参数校验 101 | if (StringUtils.isBlank(ak)) throw new NullPointerException("⚠ 请填写开发者密钥"); 102 | if (StringUtils.isNotBlank(ip) && CommonUtil.checkIp(ip)) { 103 | if ("localhost".equals(ip) || "127.0.0.1".equals(ip) || "::1".equals(ip)) { 104 | ip = ""; 105 | } 106 | } else { 107 | ip = ""; 108 | } 109 | 110 | // 2、发送URL请求 111 | String url = "https://api.map.baidu.com/location/ip?ip=" + ip + "&coor=bd09ll&&ak=" + ak; 112 | JSONObject data = sendUrl(url); 113 | 114 | // 3、获取数据 115 | String address; 116 | if (data.get("status").toString().equals("0")) { 117 | address = data.getJSONObject("content").getString("address"); // 简要地址信息 118 | } else { 119 | throw new NullPointerException("⚠ 定位异常"); 120 | } 121 | 122 | return address; 123 | 124 | } 125 | 126 | //---------------------------------------------------------------------------------------------------------------------------------------------------- 127 | 128 | /** 129 | * 发送URL请求 130 | * 131 | * @param url URL路径 132 | * @return 数据 133 | */ 134 | private static JSONObject sendUrl(String url) { 135 | 136 | StringBuilder json = new StringBuilder(); 137 | 138 | try { 139 | URL oracle = new URL(url); 140 | URLConnection uc = oracle.openConnection(); 141 | InputStreamReader isr = new InputStreamReader(uc.getInputStream(), StandardCharsets.UTF_8); 142 | BufferedReader br = new BufferedReader(isr); 143 | String inputLine; 144 | while (null != (inputLine = br.readLine())) { 145 | json.append(inputLine); 146 | } 147 | br.close(); 148 | } catch (Exception e) { 149 | throw new NullPointerException("⚠ 系统异常"); 150 | } 151 | 152 | return JSONObject.parseObject(json.toString()); 153 | 154 | } 155 | 156 | 157 | } 158 | -------------------------------------------------------------------------------- /src/main/java/fun/diviner/aidiviner/diviner/util/CommonUtil.java: -------------------------------------------------------------------------------- 1 | package fun.diviner.aidiviner.diviner.util; 2 | 3 | import java.math.BigDecimal; 4 | import java.util.*; 5 | 6 | import com.nlf.calendar.Lunar; 7 | import com.nlf.calendar.Solar; 8 | import org.apache.commons.validator.routines.InetAddressValidator; 9 | 10 | /** 11 | * 通用工具 12 | */ 13 | public class CommonUtil { 14 | 15 | /** 16 | * 二十四小时对应十二地支 17 | */ 18 | public static final String[] HOUR_ZHI = { 19 | "子", "丑", "丑", "寅", "寅", "卯", "卯", "辰", "辰", "巳", "巳", "午", "午", "未", "未", "申", "申", "酉", "酉", "戌", "戌", "亥", "亥", "子" 20 | }; 21 | 22 | //**************************************************************************************************************************************************** 23 | 24 | /** 25 | * 格式化公历日期 26 | * 27 | * @param solar 公历日期 28 | * @return 公历日期 29 | */ 30 | public static String solarStr(Solar solar) { 31 | 32 | return solar.getYear() + "年" + solar.getMonth() + "月" + solar.getDay() + "日" + solar.getHour() + "时"; 33 | 34 | } 35 | 36 | /** 37 | * 格式化农历日期 38 | * 39 | * @param lunar 农历日期 40 | * @return 农历日期 41 | */ 42 | public static String lunarStr(Lunar lunar) { 43 | 44 | String lunarStr; 45 | 46 | // 判断时辰 47 | int hour = lunar.getHour(); 48 | if (hour >= 23 || hour < 1) { 49 | // 判断早晚子时 50 | if (hour >= 23) { 51 | lunarStr = lunar + "(晚)子时"; 52 | } else { 53 | lunarStr = lunar + "(早)子时"; 54 | } 55 | } else { 56 | lunarStr = lunar + HOUR_ZHI[hour] + "时"; 57 | } 58 | 59 | return lunarStr; 60 | 61 | } 62 | 63 | /** 64 | * 机器ip校验 65 | * 66 | * @param ip 机器ip(ipv4或ipv6) 67 | * @return true:格式正确。false:格式错误 68 | */ 69 | public static boolean checkIp(String ip) { 70 | 71 | boolean isFlag = true; 72 | InetAddressValidator validator = InetAddressValidator.getInstance(); 73 | if (!validator.isValidInet4Address(ip) && !validator.isValidInet6Address(ip)) { 74 | isFlag = false; 75 | } 76 | return isFlag; 77 | 78 | } 79 | 80 | /** 81 | * 保留Double型数据的N位小数 82 | * 83 | * @param number double类型数据 84 | * @param count 保留小数的位数 85 | * @return double型数据 86 | */ 87 | public static Double getDouble(double number, int count) { 88 | 89 | BigDecimal bigDec = new BigDecimal(number); 90 | return bigDec.setScale(count, BigDecimal.ROUND_FLOOR).doubleValue(); 91 | 92 | } 93 | 94 | /** 95 | * 向List集合中添加指定个数的字符串 96 | * 97 | * @param count 元素数量 98 | * @return 空list集合 99 | */ 100 | public static List addCharToList(int count) { 101 | 102 | List list = new ArrayList<>(); 103 | for (int i = 0; i <= (count - 1); i++) { 104 | list.add(""); 105 | } 106 | return list; 107 | 108 | } 109 | 110 | /** 111 | * 获取两个List数组中的不同元素 112 | * 113 | * @param list1 数组1 114 | * @param list2 数组2 115 | * @return 不同元素的数组 116 | */ 117 | public static List getListUnlike(List list1, List list2) { 118 | 119 | List maxList = list1; 120 | List minList = list2; 121 | if (list2.size() > list1.size()) { 122 | maxList = list2; 123 | minList = list1; 124 | } 125 | 126 | Map map = new HashMap<>(list1.size() + list2.size()); 127 | for (String string : maxList) { 128 | map.put(string, 1); 129 | } 130 | for (String string : minList) { 131 | Integer count = map.get(string); 132 | if (null != count) { 133 | map.put(string, ++count); 134 | continue; 135 | } 136 | map.put(string, 1); 137 | } 138 | 139 | List unlike = new ArrayList<>(); 140 | for (Map.Entry entry : map.entrySet()) { 141 | if (entry.getValue() == 1) { 142 | unlike.add(entry.getKey()); 143 | } 144 | } 145 | 146 | return unlike; 147 | 148 | } 149 | 150 | /** 151 | * 获取list集合里出现的重复元素及出现次数 152 | * 153 | * @param list List数据 154 | * @return key:元素 value:元素重复的次数 155 | */ 156 | public static Map getListIdentical(List list) { 157 | 158 | Map map = new HashMap<>(); 159 | for (String item : list) { 160 | // 记录当前元素出现的次数 161 | int count = 1; 162 | // 若当前元素在map容器中已存在,计数器+1 163 | if (null != map.get(item)) { 164 | count = map.get(item) + 1; 165 | } 166 | // 向map容器里存数据 167 | map.put(item, count); 168 | } 169 | 170 | return map; 171 | 172 | } 173 | 174 | /** 175 | * 删除list集合中的指定的元素 176 | * 177 | * @param list List集合 178 | * @param element 需要删除的元素 179 | */ 180 | public static void removeElementList(List list, String element) { 181 | 182 | for (int i = 0; i < list.size(); i++) { 183 | if (element.equals(list.get(i))) { 184 | list.remove(i); 185 | i--; 186 | } 187 | } 188 | 189 | } 190 | 191 | /** 192 | * 删除list数组中重复的元素 193 | * 194 | * @param list list数组 195 | * @return list数组 196 | */ 197 | public static List removeDuplicates(List list) { 198 | 199 | // 删除所有null 200 | list.removeAll(Collections.singleton(null)); 201 | 202 | // 删除所有重复数据 203 | Set set = new LinkedHashSet<>(list); 204 | return new ArrayList<>(set); 205 | 206 | } 207 | 208 | /** 209 | * 获取指定个数的随机数 210 | * 211 | * @param count 数量 212 | * @param range 范围(如→ 0:产生0,1:产生0~1中的随机一位数字,2:产生0~2中的随机一位数字,... ) 213 | * @return List随机数集合 214 | */ 215 | public static List randomList(long count, int range) { 216 | 217 | List list = new ArrayList<>(); 218 | 219 | for (int i = 0; i < count; i++) { 220 | list.add(new Random().nextInt(range + 1)); 221 | } 222 | 223 | return list; 224 | 225 | } 226 | 227 | /** 228 | * 将N个数据封装为List集合,若数据<0时默认为0,若数据>3时默认为3 229 | * 230 | * @param parameter 数据 231 | * @return List集合 232 | */ 233 | public static List packageList(int... parameter) { 234 | 235 | List list = new ArrayList<>(); 236 | for (int i : parameter) { 237 | if (i < 0) i = 0; 238 | if (i > 3) i = 3; 239 | list.add(i); 240 | } 241 | return list; 242 | 243 | } 244 | 245 | /** 246 | * 数字转换汉字 247 | * 248 | * @param number 数字 249 | * @return 汉字(例如:一) 250 | */ 251 | public static String shuToHan(long number) { 252 | 253 | final String[] unit = {"", "十", "百", "千", "万", "十", "百", "千", "亿", "十", "百", "千"}; 254 | final String[] lowercaseNumber = {"零", "一", "二", "三", "四", "五", "六", "七", "八", "九"}; 255 | 256 | int count = 0; 257 | StringBuilder sb = new StringBuilder(); 258 | while (number > 0) { 259 | sb.insert(0, (lowercaseNumber[Math.toIntExact(number % 10)] + unit[count])); 260 | number = (number / 10); 261 | count++; 262 | } 263 | 264 | return sb.toString().replaceAll("零[千百十]", "零").replaceAll("零+万", "万") 265 | .replaceAll("零+亿", "亿").replaceAll("亿万", "亿零") 266 | .replaceAll("零+", "零").replaceAll("零$", ""); 267 | 268 | } 269 | 270 | 271 | } 272 | -------------------------------------------------------------------------------- /src/main/java/fun/diviner/aidiviner/diviner/util/DateUtil.java: -------------------------------------------------------------------------------- 1 | package fun.diviner.aidiviner.diviner.util; 2 | 3 | import java.text.SimpleDateFormat; 4 | import java.time.LocalDateTime; 5 | import java.time.format.DateTimeFormatter; 6 | import java.time.temporal.ChronoUnit; 7 | import java.util.*; 8 | 9 | /** 10 | * 时间工具 11 | */ 12 | public class DateUtil { 13 | 14 | /** 15 | * 在日期上增加或减少小时数、分钟数、秒数 16 | * 17 | * @param date 日期 18 | * @param iHour 要增加或减少的小时数 19 | * @param iMinute 要增加或减少的分钟数 20 | * @param iSecond 要增加或减少的秒数 21 | */ 22 | public static Date updateDate(Date date, int iHour, int iMinute, int iSecond) { 23 | 24 | Calendar c = Calendar.getInstance(); 25 | 26 | c.setTime(date); 27 | c.add(Calendar.HOUR_OF_DAY, iHour); // 小时 28 | c.add(Calendar.MINUTE, iMinute); // 分钟 29 | c.add(Calendar.SECOND, iSecond); // 秒 30 | 31 | return c.getTime(); 32 | 33 | } 34 | 35 | /** 36 | * 获取日期的[年月日时分秒] 37 | * 38 | * @param date 日期 39 | * @return 年月日时分秒 40 | */ 41 | public static Map getDateMap(Date date) { 42 | 43 | Calendar c = Calendar.getInstance(); 44 | c.setTime(date); 45 | 46 | Map map = new HashMap<>(); 47 | map.put("year", c.get(Calendar.YEAR)); // 年 48 | map.put("month", c.get(Calendar.MONTH) + 1); // 月 49 | map.put("day", c.get(Calendar.DATE)); // 日 50 | map.put("hour", c.get(Calendar.HOUR_OF_DAY)); // 时 51 | map.put("minute", c.get(Calendar.MINUTE)); // 分 52 | map.put("second", c.get(Calendar.SECOND)); // 秒 53 | 54 | return map; 55 | 56 | } 57 | 58 | /** 59 | * 获取指定日期字符串 60 | * 61 | * @param date Date型日期 62 | * @param dateFormat 日期格式 63 | * @return String型日期 64 | */ 65 | public static String getDateStr(Date date, String dateFormat) { 66 | 67 | String dateStr; 68 | SimpleDateFormat sdf = new SimpleDateFormat(dateFormat); 69 | sdf.setTimeZone(TimeZone.getTimeZone("GMT+8")); 70 | dateStr = sdf.format(date); 71 | return dateStr; 72 | 73 | } 74 | 75 | /** 76 | * 计算两个日期的时间间隔 77 | * 78 | * @param startDate 开始日期 79 | * @param endDate 结束日期 80 | * @return 时间间隔 81 | */ 82 | public static Map dateInterval(String startDate, String endDate) { 83 | 84 | DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"); 85 | LocalDateTime sDate = LocalDateTime.parse(startDate, formatter); // 开始日期 86 | LocalDateTime eDate = LocalDateTime.parse(endDate, formatter); // 结束日期 87 | 88 | Long days = ChronoUnit.DAYS.between(sDate, eDate); 89 | Long hours = ChronoUnit.HOURS.between(sDate, eDate) % 24; 90 | Long minutes = ChronoUnit.MINUTES.between(sDate, eDate) % 60; 91 | Long seconds = ChronoUnit.SECONDS.between(sDate, eDate) % 60; 92 | 93 | Map map = new HashMap<>(); 94 | map.put("days", days); // 相差天数 95 | map.put("hours", hours); // 相差小时数 96 | map.put("minutes", minutes); // 相差分钟数 97 | map.put("seconds", seconds); // 相差秒数 98 | 99 | return map; 100 | 101 | } 102 | 103 | 104 | } 105 | -------------------------------------------------------------------------------- /src/main/java/fun/diviner/aidiviner/dto/common/GetRecordIdParameter.java: -------------------------------------------------------------------------------- 1 | package fun.diviner.aidiviner.dto.common; 2 | 3 | import jakarta.validation.constraints.Min; 4 | import lombok.Data; 5 | 6 | @Data 7 | public class GetRecordIdParameter { 8 | @Min(value=1, message="每页数量仅能大于1") 9 | private int pageSize = 1000; 10 | 11 | @Min(value=1, message="页码仅能大于1") 12 | private int pageNumber = 1; 13 | } -------------------------------------------------------------------------------- /src/main/java/fun/diviner/aidiviner/dto/common/GetRecordParameter.java: -------------------------------------------------------------------------------- 1 | package fun.diviner.aidiviner.dto.common; 2 | 3 | import jakarta.validation.constraints.NotEmpty; 4 | import lombok.Data; 5 | 6 | @Data 7 | public class GetRecordParameter { 8 | @NotEmpty(message="ID不能为空") 9 | private String id; 10 | } -------------------------------------------------------------------------------- /src/main/java/fun/diviner/aidiviner/dto/tool/bazi/BaZiArrangeParameter.java: -------------------------------------------------------------------------------- 1 | package fun.diviner.aidiviner.dto.tool.bazi; 2 | 3 | import jakarta.validation.constraints.NotNull; 4 | import jakarta.validation.constraints.NotEmpty; 5 | 6 | import lombok.Data; 7 | 8 | @Data 9 | public class BaZiArrangeParameter { 10 | @NotNull(message="年不能为空") 11 | private Integer year; 12 | 13 | @NotNull(message="月不能为空") 14 | private Integer month; 15 | 16 | @NotNull(message="日不能为空") 17 | private Integer day; 18 | 19 | @NotNull(message="时不能为空") 20 | private Integer hour; 21 | 22 | @NotNull(message="分不能为空") 23 | private Integer minute; 24 | 25 | @NotEmpty(message="性别不能为空") 26 | private String gender; 27 | } -------------------------------------------------------------------------------- /src/main/java/fun/diviner/aidiviner/dto/tool/bazi/BaZiSolveParameter.java: -------------------------------------------------------------------------------- 1 | package fun.diviner.aidiviner.dto.tool.bazi; 2 | 3 | import jakarta.validation.constraints.NotEmpty; 4 | import jakarta.validation.constraints.NotNull; 5 | 6 | import lombok.Data; 7 | 8 | @Data 9 | public class BaZiSolveParameter { 10 | @NotEmpty(message="性别不能为空") 11 | private String gender; 12 | 13 | @NotEmpty(message="八字不能为空") 14 | private String bazi; 15 | 16 | @NotNull(message="大运不能为空") 17 | private String dayun; 18 | 19 | @NotNull(message="流年不能为空") 20 | private String liunian; 21 | } -------------------------------------------------------------------------------- /src/main/java/fun/diviner/aidiviner/dto/tool/liuyao/LiuYaoArrangeParameter.java: -------------------------------------------------------------------------------- 1 | package fun.diviner.aidiviner.dto.tool.liuyao; 2 | 3 | import jakarta.validation.constraints.NotEmpty; 4 | import java.util.List; 5 | 6 | import lombok.Data; 7 | 8 | /** 9 | * @author Coaixy 10 | * @createTime 2024-11-27 11 | * @packageName fun.diviner.dto.tool.liuyao 12 | **/ 13 | 14 | @Data 15 | public class LiuYaoArrangeParameter { 16 | @NotEmpty(message="数据不能为空") 17 | private List data; 18 | } -------------------------------------------------------------------------------- /src/main/java/fun/diviner/aidiviner/dto/tool/meihua/MeiHuaArrangeParameter.java: -------------------------------------------------------------------------------- 1 | package fun.diviner.aidiviner.dto.tool.meihua; 2 | 3 | import jakarta.validation.constraints.NotEmpty; 4 | import jakarta.validation.constraints.Max; 5 | import jakarta.validation.constraints.Min; 6 | 7 | import lombok.Data; 8 | 9 | /** 10 | * @author Coaixy 11 | * @createTime 2024-11-20 12 | * @packageName fun.diviner.dto.tool.meihua 13 | **/ 14 | 15 | @Data 16 | public class MeiHuaArrangeParameter { 17 | @NotEmpty(message="类型不能为空") 18 | private String type; 19 | 20 | @Min(value=10, message="数字仅能为10~2147483647的整数") 21 | @Max(value=2147483647, message="数字仅能为10~2147483647的整数") 22 | private int number; 23 | } -------------------------------------------------------------------------------- /src/main/java/fun/diviner/aidiviner/dto/tool/meihua/MeiHuaSolveParameter.java: -------------------------------------------------------------------------------- 1 | package fun.diviner.aidiviner.dto.tool.meihua; 2 | 3 | import jakarta.validation.constraints.NotNull; 4 | import jakarta.validation.constraints.NotEmpty; 5 | 6 | import lombok.Data; 7 | 8 | import fun.diviner.aidiviner.diviner.type.MeiHuaArrangeResponse; 9 | 10 | /** 11 | * @author Coaixy 12 | * @createTime 2024-11-22 13 | * @packageName fun.diviner.dto.tool.meihua 14 | **/ 15 | 16 | @Data 17 | public class MeiHuaSolveParameter { 18 | @NotNull(message="卦局不能为空") 19 | MeiHuaArrangeResponse arrangeResponse; 20 | 21 | @NotEmpty(message="问题不能为空") 22 | String question; 23 | } -------------------------------------------------------------------------------- /src/main/java/fun/diviner/aidiviner/dto/tool/tarot/TarotCommonParameter.java: -------------------------------------------------------------------------------- 1 | package fun.diviner.aidiviner.dto.tool.tarot; 2 | 3 | import jakarta.validation.constraints.NotEmpty; 4 | 5 | import lombok.Data; 6 | 7 | @Data 8 | public class TarotCommonParameter { 9 | @NotEmpty(message="问题不能为空") 10 | private String question; 11 | } -------------------------------------------------------------------------------- /src/main/java/fun/diviner/aidiviner/dto/tool/tarot/TarotSelectParameter.java: -------------------------------------------------------------------------------- 1 | package fun.diviner.aidiviner.dto.tool.tarot; 2 | 3 | import jakarta.validation.constraints.NotEmpty; 4 | import java.util.List; 5 | 6 | import lombok.Data; 7 | 8 | @Data 9 | public class TarotSelectParameter { 10 | @NotEmpty(message="牌阵不能为空") 11 | private String spreadName; 12 | 13 | @NotEmpty(message="牌不能为空") 14 | private List cardIndexList; 15 | 16 | @NotEmpty(message="问题不能为空") 17 | private String question; 18 | } -------------------------------------------------------------------------------- /src/main/java/fun/diviner/aidiviner/dto/tool/xiaoliuren/XiaoLiuRenSolveParameter.java: -------------------------------------------------------------------------------- 1 | package fun.diviner.aidiviner.dto.tool.xiaoliuren; 2 | 3 | import jakarta.validation.constraints.NotEmpty; 4 | import jakarta.validation.constraints.Size; 5 | import java.util.List; 6 | 7 | import lombok.Data; 8 | 9 | /** 10 | * @author Coaixy 11 | * @createTime 2024-12-02 12 | * @packageName fun.diviner.dto.tool.xiaoliu 13 | **/ 14 | 15 | @Data 16 | public class XiaoLiuRenSolveParameter { 17 | @NotEmpty(message = "问题不能为空") 18 | private String question; 19 | 20 | @NotEmpty(message = "神不能为空") 21 | @Size(min=3, max=3, message="神的长度仅能为3") 22 | private List liushen; 23 | } -------------------------------------------------------------------------------- /src/main/java/fun/diviner/aidiviner/dto/user/GetRechargeParameter.java: -------------------------------------------------------------------------------- 1 | package fun.diviner.aidiviner.dto.user; 2 | 3 | import jakarta.validation.constraints.Min; 4 | 5 | import lombok.Data; 6 | 7 | @Data 8 | public class GetRechargeParameter { 9 | @Min(value=1, message="每页数量仅能大于1") 10 | private int pageSize = 30; 11 | 12 | @Min(value=1, message="页码仅能大于1") 13 | private int pageNumber = 1; 14 | } -------------------------------------------------------------------------------- /src/main/java/fun/diviner/aidiviner/dto/user/GetRecordParameter.java: -------------------------------------------------------------------------------- 1 | package fun.diviner.aidiviner.dto.user; 2 | 3 | import jakarta.validation.constraints.NotNull; 4 | import jakarta.validation.constraints.Min; 5 | 6 | import lombok.Data; 7 | 8 | @Data 9 | public class GetRecordParameter { 10 | @NotNull(message="工具ID不能为空") 11 | private Integer toolId; 12 | 13 | @Min(value=1, message="每页数量仅能大于1") 14 | private int pageSize = 30; 15 | 16 | @Min(value=1, message="页码仅能大于1") 17 | private int pageNumber = 1; 18 | } -------------------------------------------------------------------------------- /src/main/java/fun/diviner/aidiviner/dto/user/ModifyAccountParameter.java: -------------------------------------------------------------------------------- 1 | package fun.diviner.aidiviner.dto.user; 2 | 3 | import jakarta.validation.constraints.Pattern; 4 | 5 | import lombok.Data; 6 | 7 | @Data 8 | public class ModifyAccountParameter { 9 | @Pattern(regexp="[A-Za-z0-9]{5,15}$", message="密码仅能为5~15长度的数字和字母") 10 | private String password; 11 | 12 | public void setPassword(String password) { 13 | this.password = password.isEmpty() ? null : password; 14 | } 15 | } -------------------------------------------------------------------------------- /src/main/java/fun/diviner/aidiviner/dto/user/OpenVIPParameter.java: -------------------------------------------------------------------------------- 1 | package fun.diviner.aidiviner.dto.user; 2 | 3 | import jakarta.validation.constraints.NotNull; 4 | 5 | import lombok.Data; 6 | 7 | @Data 8 | public class OpenVIPParameter { 9 | @NotNull(message="ID不能为空") 10 | private Integer id; 11 | } -------------------------------------------------------------------------------- /src/main/java/fun/diviner/aidiviner/dto/user/RechargeParameter.java: -------------------------------------------------------------------------------- 1 | package fun.diviner.aidiviner.dto.user; 2 | 3 | import jakarta.validation.constraints.NotNull; 4 | import jakarta.validation.constraints.Min; 5 | import jakarta.validation.constraints.Max; 6 | import jakarta.validation.constraints.NotEmpty; 7 | import jakarta.validation.constraints.Pattern; 8 | 9 | import lombok.Data; 10 | 11 | import fun.diviner.aidiviner.entity.Special; 12 | 13 | @Data 14 | public class RechargeParameter { 15 | @NotNull(message="积分不能为空") 16 | @Min(value=Special.moneyPointProportion, message="积分仅能为" + Special.moneyPointProportion + "~" + 1000 * Special.moneyPointProportion + "的整数") 17 | @Max(value=1000 * Special.moneyPointProportion, message="积分仅能为" + Special.moneyPointProportion + "~" + 1000 * Special.moneyPointProportion + "的整数") 18 | private Integer point; 19 | 20 | @NotEmpty(message="类型不能为空") 21 | @Pattern(regexp="ali|wechat", message="类型仅能为ali,wechat,ali代表支付宝,wechat代表微信") 22 | private String type; 23 | } -------------------------------------------------------------------------------- /src/main/java/fun/diviner/aidiviner/dto/user/RegisterLoginParameter.java: -------------------------------------------------------------------------------- 1 | package fun.diviner.aidiviner.dto.user; 2 | 3 | import jakarta.validation.constraints.NotEmpty; 4 | import jakarta.validation.constraints.Pattern; 5 | 6 | import lombok.Data; 7 | 8 | @Data 9 | public class RegisterLoginParameter { 10 | @NotEmpty(message="手机号不能为空") 11 | @Pattern(regexp="^1[3-9]\\d{9}$", message="手机号仅能为中国大陆的手机号") 12 | private String phoneNumber; 13 | 14 | @NotEmpty(message="密码不能为空") 15 | @Pattern(regexp="[A-Za-z0-9]{5,15}$", message="密码仅能为5~15长度的数字和字母") 16 | private String password; 17 | } -------------------------------------------------------------------------------- /src/main/java/fun/diviner/aidiviner/dto/user/UseCardParameter.java: -------------------------------------------------------------------------------- 1 | package fun.diviner.aidiviner.dto.user; 2 | 3 | import jakarta.validation.constraints.NotEmpty; 4 | 5 | import lombok.Data; 6 | 7 | @Data 8 | public class UseCardParameter { 9 | @NotEmpty(message="码不能为空") 10 | private String code; 11 | } -------------------------------------------------------------------------------- /src/main/java/fun/diviner/aidiviner/entity/Auth.java: -------------------------------------------------------------------------------- 1 | package fun.diviner.aidiviner.entity; 2 | 3 | import lombok.Data; 4 | 5 | @Data 6 | public class Auth { 7 | private int id; 8 | private String token; 9 | } -------------------------------------------------------------------------------- /src/main/java/fun/diviner/aidiviner/entity/Pay.java: -------------------------------------------------------------------------------- 1 | package fun.diviner.aidiviner.entity; 2 | 3 | import lombok.Data; 4 | 5 | @Data 6 | public class Pay { 7 | private PayType type; 8 | private int reward; 9 | private int recharge; 10 | private boolean state; 11 | } -------------------------------------------------------------------------------- /src/main/java/fun/diviner/aidiviner/entity/PayType.java: -------------------------------------------------------------------------------- 1 | package fun.diviner.aidiviner.entity; 2 | 3 | public enum PayType { 4 | FREE, 5 | RECHARGE_BALANCE, 6 | BALANCE 7 | } -------------------------------------------------------------------------------- /src/main/java/fun/diviner/aidiviner/entity/Special.java: -------------------------------------------------------------------------------- 1 | package fun.diviner.aidiviner.entity; 2 | 3 | public class Special { 4 | public static String authSecret = "AI-Diviner-Backend-Backend-Backend-1739116315"; 5 | public static class AttributeName { 6 | public static String user = "user"; 7 | public static String trade = "trade"; 8 | } 9 | public static class RedisSurvivalTime { 10 | public static int captcha = 30; 11 | public static int accessToken = 7; 12 | } 13 | public static int commonGroupId = 1; 14 | public static class CoreName { 15 | public static String openTool = "openTool"; 16 | public static String yiPayId = "yiPayId"; 17 | public static String yiPayMerchantPrivateKey = "yiPayMerchantPrivateKey"; 18 | public static String yiPayNoticeUrlPrefix = "yiPayNoticeUrlPrefix"; 19 | public static String yiPayReturnUrl = "yiPayReturnUrl"; 20 | public static String yiPayPlatformPublicKey = "yiPayPlatformPublicKey"; 21 | } 22 | public static final int moneyPointProportion = 10; 23 | } -------------------------------------------------------------------------------- /src/main/java/fun/diviner/aidiviner/entity/Trade.java: -------------------------------------------------------------------------------- 1 | package fun.diviner.aidiviner.entity; 2 | 3 | import lombok.Data; 4 | 5 | @Data 6 | public class Trade { 7 | private int id; 8 | private Pay pay; 9 | } -------------------------------------------------------------------------------- /src/main/java/fun/diviner/aidiviner/entity/database/Card.java: -------------------------------------------------------------------------------- 1 | package fun.diviner.aidiviner.entity.database; 2 | 3 | import lombok.Data; 4 | 5 | @Data 6 | public class Card { 7 | private int id; 8 | private String code; 9 | private int point; 10 | private int number; 11 | private int count; 12 | } -------------------------------------------------------------------------------- /src/main/java/fun/diviner/aidiviner/entity/database/CardRecord.java: -------------------------------------------------------------------------------- 1 | package fun.diviner.aidiviner.entity.database; 2 | 3 | import lombok.Data; 4 | 5 | @Data 6 | public class CardRecord { 7 | private int cardId; 8 | private int userId; 9 | } -------------------------------------------------------------------------------- /src/main/java/fun/diviner/aidiviner/entity/database/Core.java: -------------------------------------------------------------------------------- 1 | package fun.diviner.aidiviner.entity.database; 2 | 3 | import lombok.Data; 4 | 5 | @Data 6 | public class Core { 7 | private String name; 8 | private String content; 9 | } -------------------------------------------------------------------------------- /src/main/java/fun/diviner/aidiviner/entity/database/Group.java: -------------------------------------------------------------------------------- 1 | package fun.diviner.aidiviner.entity.database; 2 | 3 | import com.baomidou.mybatisplus.annotation.TableName; 4 | import lombok.Data; 5 | 6 | @TableName("user_group") 7 | @Data 8 | public class Group { 9 | private int id; 10 | private String name; 11 | private int checkInPoint; 12 | private int price; 13 | } -------------------------------------------------------------------------------- /src/main/java/fun/diviner/aidiviner/entity/database/Recharge.java: -------------------------------------------------------------------------------- 1 | package fun.diviner.aidiviner.entity.database; 2 | 3 | import java.math.BigDecimal; 4 | import java.time.LocalDateTime; 5 | 6 | import lombok.Data; 7 | import com.baomidou.mybatisplus.annotation.TableField; 8 | import com.baomidou.mybatisplus.annotation.FieldStrategy; 9 | 10 | @Data 11 | public class Recharge { 12 | private String id; 13 | private int point; 14 | private BigDecimal money; 15 | private String url; 16 | 17 | @TableField(insertStrategy=FieldStrategy.NEVER) 18 | private boolean state; 19 | 20 | @TableField(insertStrategy=FieldStrategy.NEVER) 21 | private LocalDateTime creationTime; 22 | 23 | @TableField(insertStrategy=FieldStrategy.NEVER) 24 | private LocalDateTime paymentTime; 25 | 26 | private int userId; 27 | } -------------------------------------------------------------------------------- /src/main/java/fun/diviner/aidiviner/entity/database/Record.java: -------------------------------------------------------------------------------- 1 | package fun.diviner.aidiviner.entity.database; 2 | 3 | import java.time.LocalDateTime; 4 | 5 | import lombok.Data; 6 | import com.baomidou.mybatisplus.annotation.TableField; 7 | import com.baomidou.mybatisplus.annotation.FieldStrategy; 8 | 9 | @Data 10 | public class Record { 11 | private String id; 12 | private int toolId; 13 | private String request; 14 | private String response; 15 | 16 | @TableField(value="time_", insertStrategy=FieldStrategy.NEVER) 17 | private LocalDateTime time; 18 | 19 | private int userId; 20 | } -------------------------------------------------------------------------------- /src/main/java/fun/diviner/aidiviner/entity/database/Tool.java: -------------------------------------------------------------------------------- 1 | package fun.diviner.aidiviner.entity.database; 2 | 3 | import lombok.Data; 4 | 5 | @Data 6 | public class Tool { 7 | private int id; 8 | private String name; 9 | private String alias; 10 | private int price; 11 | } -------------------------------------------------------------------------------- /src/main/java/fun/diviner/aidiviner/entity/database/ToolTarotCard.java: -------------------------------------------------------------------------------- 1 | package fun.diviner.aidiviner.entity.database; 2 | 3 | import lombok.Data; 4 | 5 | @Data 6 | public class ToolTarotCard { 7 | private int id; 8 | private String name; 9 | private String description; 10 | private String normal; 11 | private String reversed; 12 | private String detail; 13 | private String link; 14 | } -------------------------------------------------------------------------------- /src/main/java/fun/diviner/aidiviner/entity/database/ToolTarotSpread.java: -------------------------------------------------------------------------------- 1 | package fun.diviner.aidiviner.entity.database; 2 | 3 | import lombok.Data; 4 | 5 | @Data 6 | public class ToolTarotSpread { 7 | private int id; 8 | private String name; 9 | private String description; 10 | private String card; 11 | } -------------------------------------------------------------------------------- /src/main/java/fun/diviner/aidiviner/entity/database/User.java: -------------------------------------------------------------------------------- 1 | package fun.diviner.aidiviner.entity.database; 2 | 3 | import java.time.LocalDateTime; 4 | 5 | import com.baomidou.mybatisplus.annotation.*; 6 | import lombok.Data; 7 | 8 | @Data 9 | public class User { 10 | @TableId(type=IdType.AUTO) 11 | private int id; 12 | 13 | private String phoneNumber; 14 | private String password; 15 | 16 | @TableField(insertStrategy=FieldStrategy.NEVER) 17 | private int rewardBalance; 18 | 19 | @TableField(insertStrategy=FieldStrategy.NEVER) 20 | private int rechargeBalance; 21 | 22 | @TableField(insertStrategy=FieldStrategy.NEVER) 23 | private boolean checkIn; 24 | 25 | @TableField(insertStrategy=FieldStrategy.NEVER) 26 | private int groupId; 27 | 28 | @TableField(insertStrategy=FieldStrategy.NEVER) 29 | private LocalDateTime groupExpirationTime; 30 | } -------------------------------------------------------------------------------- /src/main/java/fun/diviner/aidiviner/mapper/CardMapper.java: -------------------------------------------------------------------------------- 1 | package fun.diviner.aidiviner.mapper; 2 | 3 | import org.springframework.stereotype.Repository; 4 | import com.baomidou.mybatisplus.core.mapper.BaseMapper; 5 | 6 | import fun.diviner.aidiviner.entity.database.Card; 7 | 8 | @Repository 9 | public interface CardMapper extends BaseMapper { 10 | 11 | } -------------------------------------------------------------------------------- /src/main/java/fun/diviner/aidiviner/mapper/CardRecordMapper.java: -------------------------------------------------------------------------------- 1 | package fun.diviner.aidiviner.mapper; 2 | 3 | import org.springframework.stereotype.Repository; 4 | import com.baomidou.mybatisplus.core.mapper.BaseMapper; 5 | 6 | import fun.diviner.aidiviner.entity.database.CardRecord; 7 | 8 | @Repository 9 | public interface CardRecordMapper extends BaseMapper { 10 | 11 | } -------------------------------------------------------------------------------- /src/main/java/fun/diviner/aidiviner/mapper/CoreMapper.java: -------------------------------------------------------------------------------- 1 | package fun.diviner.aidiviner.mapper; 2 | 3 | import org.springframework.stereotype.Repository; 4 | import com.baomidou.mybatisplus.core.mapper.BaseMapper; 5 | 6 | import fun.diviner.aidiviner.entity.database.Core; 7 | 8 | @Repository 9 | public interface CoreMapper extends BaseMapper { 10 | 11 | } -------------------------------------------------------------------------------- /src/main/java/fun/diviner/aidiviner/mapper/GroupMapper.java: -------------------------------------------------------------------------------- 1 | package fun.diviner.aidiviner.mapper; 2 | 3 | import org.springframework.stereotype.Repository; 4 | import com.baomidou.mybatisplus.core.mapper.BaseMapper; 5 | 6 | import fun.diviner.aidiviner.entity.database.Group; 7 | 8 | @Repository 9 | public interface GroupMapper extends BaseMapper { 10 | 11 | } -------------------------------------------------------------------------------- /src/main/java/fun/diviner/aidiviner/mapper/RechargeMapper.java: -------------------------------------------------------------------------------- 1 | package fun.diviner.aidiviner.mapper; 2 | 3 | import org.springframework.stereotype.Repository; 4 | import com.baomidou.mybatisplus.core.mapper.BaseMapper; 5 | 6 | import fun.diviner.aidiviner.entity.database.Recharge; 7 | 8 | @Repository 9 | public interface RechargeMapper extends BaseMapper { 10 | 11 | } -------------------------------------------------------------------------------- /src/main/java/fun/diviner/aidiviner/mapper/RecordMapper.java: -------------------------------------------------------------------------------- 1 | package fun.diviner.aidiviner.mapper; 2 | 3 | import org.springframework.stereotype.Repository; 4 | import com.baomidou.mybatisplus.core.mapper.BaseMapper; 5 | 6 | import fun.diviner.aidiviner.entity.database.Record; 7 | 8 | @Repository 9 | public interface RecordMapper extends BaseMapper { 10 | 11 | } -------------------------------------------------------------------------------- /src/main/java/fun/diviner/aidiviner/mapper/ToolMapper.java: -------------------------------------------------------------------------------- 1 | package fun.diviner.aidiviner.mapper; 2 | 3 | import org.springframework.stereotype.Repository; 4 | import com.baomidou.mybatisplus.core.mapper.BaseMapper; 5 | 6 | import fun.diviner.aidiviner.entity.database.Tool; 7 | 8 | @Repository 9 | public interface ToolMapper extends BaseMapper { 10 | 11 | } -------------------------------------------------------------------------------- /src/main/java/fun/diviner/aidiviner/mapper/ToolTarotCardMapper.java: -------------------------------------------------------------------------------- 1 | package fun.diviner.aidiviner.mapper; 2 | 3 | import org.springframework.stereotype.Repository; 4 | import com.baomidou.mybatisplus.core.mapper.BaseMapper; 5 | 6 | import fun.diviner.aidiviner.entity.database.ToolTarotCard; 7 | 8 | @Repository 9 | public interface ToolTarotCardMapper extends BaseMapper { 10 | 11 | } -------------------------------------------------------------------------------- /src/main/java/fun/diviner/aidiviner/mapper/ToolTarotSpreadMapper.java: -------------------------------------------------------------------------------- 1 | package fun.diviner.aidiviner.mapper; 2 | 3 | import org.springframework.stereotype.Repository; 4 | import com.baomidou.mybatisplus.core.mapper.BaseMapper; 5 | 6 | import fun.diviner.aidiviner.entity.database.ToolTarotSpread; 7 | 8 | @Repository 9 | public interface ToolTarotSpreadMapper extends BaseMapper { 10 | 11 | } -------------------------------------------------------------------------------- /src/main/java/fun/diviner/aidiviner/mapper/UserMapper.java: -------------------------------------------------------------------------------- 1 | package fun.diviner.aidiviner.mapper; 2 | 3 | import org.springframework.stereotype.Repository; 4 | import com.baomidou.mybatisplus.core.mapper.BaseMapper; 5 | 6 | import fun.diviner.aidiviner.entity.database.User; 7 | 8 | @Repository 9 | public interface UserMapper extends BaseMapper { 10 | 11 | } -------------------------------------------------------------------------------- /src/main/java/fun/diviner/aidiviner/redis/AccessTokenRedis.java: -------------------------------------------------------------------------------- 1 | package fun.diviner.aidiviner.redis; 2 | 3 | import java.util.concurrent.TimeUnit; 4 | import java.util.Set; 5 | 6 | import org.springframework.stereotype.Component; 7 | import org.springframework.beans.factory.annotation.Autowired; 8 | import org.springframework.beans.factory.annotation.Qualifier; 9 | import org.springframework.data.redis.core.RedisTemplate; 10 | 11 | import fun.diviner.aidiviner.entity.Special; 12 | 13 | @Component 14 | public class AccessTokenRedis { 15 | @Autowired 16 | @Qualifier("accessTokenRedisBean") 17 | private RedisTemplate template; 18 | 19 | public void set(int id, String token) { 20 | this.template.opsForValue().set(id + ":" + token, id, Special.RedisSurvivalTime.accessToken, TimeUnit.DAYS); 21 | } 22 | 23 | private String getKey(String token) { 24 | Set keys = this.template.keys("*:" + token); 25 | if (keys.isEmpty()) { 26 | return null; 27 | } 28 | return keys.iterator().next(); 29 | } 30 | 31 | public Integer get(String token) { 32 | String key = this.getKey(token); 33 | if (key == null) { 34 | return null; 35 | } 36 | return this.template.opsForValue().get(key); 37 | } 38 | 39 | public boolean delete(String token) { 40 | String key = this.getKey(token); 41 | if (key == null) { 42 | return false; 43 | } 44 | return this.template.delete(key); 45 | } 46 | 47 | public void delete(int id) { 48 | Set keys = this.template.keys(id + ":*"); 49 | if (keys.isEmpty()) { 50 | return; 51 | } 52 | this.template.delete(keys); 53 | } 54 | } -------------------------------------------------------------------------------- /src/main/java/fun/diviner/aidiviner/redis/CaptchaRedis.java: -------------------------------------------------------------------------------- 1 | package fun.diviner.aidiviner.redis; 2 | 3 | import java.util.concurrent.TimeUnit; 4 | 5 | import org.springframework.stereotype.Component; 6 | import org.springframework.beans.factory.annotation.Autowired; 7 | import org.springframework.beans.factory.annotation.Qualifier; 8 | import org.springframework.data.redis.core.RedisTemplate; 9 | 10 | import fun.diviner.aidiviner.entity.Special; 11 | 12 | @Component 13 | public class CaptchaRedis { 14 | @Autowired 15 | @Qualifier("captchaRedisBean") 16 | private RedisTemplate template; 17 | 18 | public void set(String key, String code) { 19 | this.template.opsForValue().set(key, code, Special.RedisSurvivalTime.captcha, TimeUnit.MINUTES); 20 | } 21 | 22 | public String get(String key) { 23 | return this.template.opsForValue().get(key); 24 | } 25 | 26 | public boolean delete(String key) { 27 | return this.template.delete(key); 28 | } 29 | } -------------------------------------------------------------------------------- /src/main/java/fun/diviner/aidiviner/service/CommonService.java: -------------------------------------------------------------------------------- 1 | package fun.diviner.aidiviner.service; 2 | 3 | import java.util.UUID; 4 | import java.util.Map; 5 | import java.util.List; 6 | import java.time.LocalDateTime; 7 | 8 | import org.springframework.stereotype.Service; 9 | import org.springframework.beans.factory.annotation.Autowired; 10 | import cn.hutool.captcha.ShearCaptcha; 11 | import cn.hutool.captcha.CaptchaUtil; 12 | import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; 13 | import com.baomidou.mybatisplus.extension.plugins.pagination.Page; 14 | 15 | import fun.diviner.aidiviner.redis.CaptchaRedis; 16 | import fun.diviner.aidiviner.mapper.ToolMapper; 17 | import fun.diviner.aidiviner.mapper.GroupMapper; 18 | import fun.diviner.aidiviner.mapper.RechargeMapper; 19 | import fun.diviner.aidiviner.mapper.UserMapper; 20 | import fun.diviner.aidiviner.mapper.RecordMapper; 21 | import fun.diviner.aidiviner.util.response.GenerateResponse; 22 | import fun.diviner.aidiviner.util.response.ExceptionResponse; 23 | import fun.diviner.aidiviner.util.response.ExceptionResponseCode; 24 | import fun.diviner.aidiviner.util.Auxiliary; 25 | import fun.diviner.aidiviner.util.yi_pay.YiPay; 26 | import fun.diviner.aidiviner.entity.database.Tool; 27 | import fun.diviner.aidiviner.entity.database.Group; 28 | import fun.diviner.aidiviner.entity.database.Recharge; 29 | import fun.diviner.aidiviner.entity.database.User; 30 | import fun.diviner.aidiviner.entity.database.Record; 31 | import fun.diviner.aidiviner.entity.Special; 32 | import fun.diviner.aidiviner.dto.common.GetRecordIdParameter; 33 | import fun.diviner.aidiviner.dto.common.GetRecordParameter; 34 | 35 | @Service 36 | public class CommonService { 37 | @Autowired 38 | private CaptchaRedis captcha; 39 | @Autowired 40 | private ToolMapper tool; 41 | @Autowired 42 | private GroupMapper group; 43 | @Autowired 44 | private UtilService util; 45 | @Autowired 46 | private RechargeMapper recharge; 47 | @Autowired 48 | private UserMapper user; 49 | @Autowired 50 | private RecordMapper record; 51 | 52 | public GenerateResponse> getCaptcha() { 53 | ShearCaptcha captcha = CaptchaUtil.createShearCaptcha(150, 50, 4, 5); 54 | String key = UUID.randomUUID().toString(); 55 | this.captcha.set(key, captcha.getCode()); 56 | return new GenerateResponse<>(Map.of( 57 | "key", key, 58 | "image", "data:image/png;base64," + captcha.getImageBase64() 59 | )); 60 | } 61 | 62 | public GenerateResponse> getTool() { 63 | return new GenerateResponse<>(this.tool.selectList(null)); 64 | } 65 | 66 | public GenerateResponse>> getVIP() { 67 | LambdaQueryWrapper wrapper = new LambdaQueryWrapper<>(); 68 | wrapper.ne(Group::getId, Special.commonGroupId); 69 | List> results = this.group.selectList(wrapper).stream().map(item -> { 70 | return Map.of( 71 | "id", item.getId(), 72 | "name", item.getName(), 73 | "checkInPoint", item.getCheckInPoint(), 74 | "price", item.getPrice() 75 | ); 76 | }).toList(); 77 | return new GenerateResponse<>(results); 78 | } 79 | 80 | public GenerateResponse yiPayCallback(Map parameter) { 81 | if (!YiPay.verify(util.getCoreContent(Special.CoreName.yiPayPlatformPublicKey), parameter)) { 82 | return new GenerateResponse<>("success"); 83 | } 84 | 85 | LambdaQueryWrapper rechargeWrapper = new LambdaQueryWrapper<>(); 86 | rechargeWrapper.eq(Recharge::getId, parameter.get("out_trade_no")); 87 | Recharge recharge = this.recharge.selectOne(rechargeWrapper); 88 | if (!recharge.isState()) { 89 | recharge.setState(true); 90 | recharge.setPaymentTime(LocalDateTime.now()); 91 | this.recharge.updateById(recharge); 92 | 93 | User user = this.user.selectById(recharge.getUserId()); 94 | user.setRechargeBalance(user.getRechargeBalance() + recharge.getPoint()); 95 | this.user.updateById(user); 96 | } 97 | return new GenerateResponse<>("success"); 98 | } 99 | 100 | public GenerateResponse> getRecordId(GetRecordIdParameter parameter) { 101 | int pageSize = parameter.getPageSize(); 102 | int pageNumber = parameter.getPageNumber(); 103 | 104 | LambdaQueryWrapper wrapper = new LambdaQueryWrapper<>(); 105 | wrapper.orderByDesc(Record::getTime); 106 | Page page = new Page<>(); 107 | page.setSize(pageSize); 108 | page.setCurrent(pageNumber); 109 | 110 | Page data = this.record.selectPage(page, wrapper); 111 | return new GenerateResponse<>(Map.of( 112 | "data", data.getRecords().stream().map(Record::getId).toList(), 113 | "total", data.getTotal() 114 | )); 115 | } 116 | 117 | public GenerateResponse> getRecord(GetRecordParameter parameter) { 118 | String id = parameter.getId(); 119 | 120 | LambdaQueryWrapper wrapper = new LambdaQueryWrapper<>(); 121 | wrapper.eq(Record::getId, id); 122 | Record data = this.record.selectOne(wrapper); 123 | if (data == null) { 124 | throw new ExceptionResponse(ExceptionResponseCode.PARAMETER_ERROR, "ID不存在"); 125 | } 126 | 127 | Tool tool = this.tool.selectById(data.getToolId()); 128 | return new GenerateResponse<>(Map.of( 129 | "tool", Map.of( 130 | "name", tool.getName(), 131 | "alias", tool.getAlias() 132 | ), 133 | "request", data.getRequest(), 134 | "response", data.getResponse(), 135 | "time", Auxiliary.localDateTimeToTimestamp(data.getTime()) 136 | )); 137 | } 138 | } -------------------------------------------------------------------------------- /src/main/java/fun/diviner/aidiviner/service/UserService.java: -------------------------------------------------------------------------------- 1 | package fun.diviner.aidiviner.service; 2 | 3 | import jakarta.servlet.http.HttpServletRequest; 4 | import java.util.UUID; 5 | import java.util.Map; 6 | import java.util.concurrent.TimeUnit; 7 | import java.util.HashMap; 8 | import java.util.List; 9 | import java.time.LocalDateTime; 10 | import java.time.Instant; 11 | import java.io.IOException; 12 | import java.math.BigDecimal; 13 | 14 | import org.springframework.stereotype.Service; 15 | import org.springframework.beans.factory.annotation.Autowired; 16 | import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; 17 | import com.baomidou.mybatisplus.extension.plugins.pagination.Page; 18 | import cn.hutool.core.util.RandomUtil; 19 | 20 | import fun.diviner.aidiviner.mapper.UserMapper; 21 | import fun.diviner.aidiviner.mapper.GroupMapper; 22 | import fun.diviner.aidiviner.mapper.CoreMapper; 23 | import fun.diviner.aidiviner.mapper.RechargeMapper; 24 | import fun.diviner.aidiviner.mapper.ToolMapper; 25 | import fun.diviner.aidiviner.mapper.RecordMapper; 26 | import fun.diviner.aidiviner.mapper.CardMapper; 27 | import fun.diviner.aidiviner.mapper.CardRecordMapper; 28 | import fun.diviner.aidiviner.util.response.GenerateResponse; 29 | import fun.diviner.aidiviner.util.response.ExceptionResponse; 30 | import fun.diviner.aidiviner.util.response.ExceptionResponseCode; 31 | import fun.diviner.aidiviner.util.Auxiliary; 32 | import fun.diviner.aidiviner.util.yi_pay.YiPayType; 33 | import fun.diviner.aidiviner.util.yi_pay.YiPay; 34 | import fun.diviner.aidiviner.util.yi_pay.YiPayResponse; 35 | import fun.diviner.aidiviner.dto.user.RegisterLoginParameter; 36 | import fun.diviner.aidiviner.dto.user.ModifyAccountParameter; 37 | import fun.diviner.aidiviner.dto.user.OpenVIPParameter; 38 | import fun.diviner.aidiviner.dto.user.RechargeParameter; 39 | import fun.diviner.aidiviner.dto.user.GetRechargeParameter; 40 | import fun.diviner.aidiviner.dto.user.GetRecordParameter; 41 | import fun.diviner.aidiviner.dto.user.UseCardParameter; 42 | import fun.diviner.aidiviner.entity.database.User; 43 | import fun.diviner.aidiviner.entity.database.Group; 44 | import fun.diviner.aidiviner.entity.database.Core; 45 | import fun.diviner.aidiviner.entity.database.Recharge; 46 | import fun.diviner.aidiviner.entity.database.Record; 47 | import fun.diviner.aidiviner.entity.database.Card; 48 | import fun.diviner.aidiviner.entity.database.CardRecord; 49 | import fun.diviner.aidiviner.entity.Special; 50 | import fun.diviner.aidiviner.entity.Auth; 51 | import fun.diviner.aidiviner.entity.PayType; 52 | import fun.diviner.aidiviner.redis.AccessTokenRedis; 53 | import fun.diviner.aidiviner.config.Interceptor.auth.JWTUtil; 54 | 55 | @Service 56 | public class UserService { 57 | @Autowired 58 | private UserMapper user; 59 | @Autowired 60 | private AccessTokenRedis accessToken; 61 | @Autowired 62 | private UtilService util; 63 | @Autowired 64 | private GroupMapper group; 65 | @Autowired 66 | private CoreMapper core; 67 | @Autowired 68 | private HttpServletRequest request; 69 | @Autowired 70 | private RechargeMapper recharge; 71 | @Autowired 72 | private ToolMapper tool; 73 | @Autowired 74 | private RecordMapper record; 75 | @Autowired 76 | private CardMapper card; 77 | @Autowired 78 | private CardRecordMapper cardRecord; 79 | 80 | public GenerateResponse> registerLogin(RegisterLoginParameter parameter) { 81 | String phoneNumber = parameter.getPhoneNumber(); 82 | String password = parameter.getPassword(); 83 | 84 | LambdaQueryWrapper wrapper = new LambdaQueryWrapper<>(); 85 | wrapper.eq(User::getPhoneNumber, phoneNumber); 86 | User user = this.user.selectOne(wrapper); 87 | if (user == null) { 88 | user = new User(); 89 | user.setPhoneNumber(phoneNumber); 90 | user.setPassword(password); 91 | this.user.insert(user); 92 | } else if (!password.equals(user.getPassword())) { 93 | throw new ExceptionResponse(ExceptionResponseCode.USER_ERROR, "密码错误"); 94 | } 95 | 96 | String accessToken = UUID.randomUUID().toString(); 97 | this.accessToken.set(user.getId(), accessToken); 98 | return new GenerateResponse<>(Map.of( 99 | "accessToken", JWTUtil.generate(Map.of( 100 | "token", accessToken 101 | ), Special.RedisSurvivalTime.accessToken, TimeUnit.DAYS) 102 | )); 103 | } 104 | 105 | public GenerateResponse logout() { 106 | this.accessToken.delete(((Auth) this.util.getAttribute(Special.AttributeName.user)).getToken()); 107 | return new GenerateResponse<>("成功"); 108 | } 109 | 110 | public GenerateResponse> getBaseInformation() { 111 | User user = this.user.selectById(this.util.getUserId()); 112 | Group group = this.group.selectById(user.getGroupId()); 113 | Map groupResult = new HashMap<>(Map.of( 114 | "name", group.getName(), 115 | "checkInPoint", group.getCheckInPoint() 116 | )); 117 | groupResult.put("expirationTime", user.getGroupExpirationTime() == null ? null : Auxiliary.localDateTimeToTimestamp(user.getGroupExpirationTime())); 118 | return new GenerateResponse<>(Map.of( 119 | "phoneNumber", user.getPhoneNumber(), 120 | "balance", Map.of( 121 | "reward", user.getRewardBalance(), 122 | "recharge", user.getRechargeBalance() 123 | ), 124 | "checkIn", user.isCheckIn(), 125 | "group", groupResult 126 | )); 127 | } 128 | 129 | public GenerateResponse modifyAccount(ModifyAccountParameter parameter) { 130 | String password = parameter.getPassword(); 131 | 132 | User user = this.user.selectById(this.util.getUserId()); 133 | if (password != null) { 134 | user.setPassword(password); 135 | this.accessToken.delete(this.util.getUserId()); 136 | } 137 | this.user.updateById(user); 138 | return new GenerateResponse<>("成功"); 139 | } 140 | 141 | public GenerateResponse checkIn() { 142 | User user = this.user.selectById(this.util.getUserId()); 143 | if (user.isCheckIn()) { 144 | throw new ExceptionResponse(ExceptionResponseCode.USER_ERROR, "已签到"); 145 | } 146 | 147 | Group group = this.group.selectById(user.getGroupId()); 148 | user.setCheckIn(true); 149 | user.setRewardBalance(user.getRewardBalance() + group.getCheckInPoint()); 150 | this.user.updateById(user); 151 | return new GenerateResponse<>("成功"); 152 | } 153 | 154 | public GenerateResponse openVIP(OpenVIPParameter parameter) { 155 | int id = parameter.getId(); 156 | 157 | Group vipGroup = this.group.selectById(id); 158 | if (vipGroup == null) { 159 | throw new ExceptionResponse(ExceptionResponseCode.PARAMETER_ERROR, "会员不存在"); 160 | } 161 | User user = this.user.selectById(this.util.getUserId()); 162 | Group userGroup = this.group.selectById(user.getGroupId()); 163 | boolean expirationIsNull = user.getGroupExpirationTime() == null; 164 | boolean expiration = !expirationIsNull && user.getGroupExpirationTime().isBefore(LocalDateTime.now()); 165 | if (user.getGroupId() != Special.commonGroupId) { 166 | if (expirationIsNull) { 167 | throw new ExceptionResponse(ExceptionResponseCode.USER_ERROR, "当前永久会员,无法开通新会员"); 168 | } else if (!expiration && vipGroup.getPrice() < userGroup.getPrice()) { 169 | throw new ExceptionResponse(ExceptionResponseCode.USER_ERROR, "当前会员未过期,仅能开通大于等于当前会员价格的会员"); 170 | } 171 | } else if (!this.util.pay(PayType.RECHARGE_BALANCE, vipGroup.getPrice()).isState()) { 172 | throw new ExceptionResponse(ExceptionResponseCode.USER_ERROR, "余额不足"); 173 | } 174 | 175 | user = this.user.selectById(this.util.getUserId()); 176 | if (expirationIsNull || expiration) { 177 | user.setGroupExpirationTime(LocalDateTime.now().plusDays(31)); 178 | } else { 179 | user.setGroupExpirationTime(user.getGroupExpirationTime().plusDays(31)); 180 | } 181 | if (id != user.getGroupId()) { 182 | user.setGroupId(id); 183 | } 184 | this.user.updateById(user); 185 | return new GenerateResponse<>("成功"); 186 | } 187 | 188 | public GenerateResponse recharge(RechargeParameter parameter) { 189 | int point = parameter.getPoint(); 190 | String type = parameter.getType(); 191 | 192 | LambdaQueryWrapper wrapper = new LambdaQueryWrapper<>(); 193 | wrapper.in(Core::getName, List.of(Special.CoreName.yiPayId, Special.CoreName.yiPayMerchantPrivateKey, Special.CoreName.yiPayNoticeUrlPrefix, Special.CoreName.yiPayReturnUrl)); 194 | List data = this.core.selectList(wrapper); 195 | int platformId = Integer.parseInt(data.get(0).getContent()); 196 | String merchantPrivateKey = data.get(1).getContent(); 197 | String noticeUrlPrefix = data.get(2).getContent(); 198 | String returnUrl = data.get(3).getContent(); 199 | String tradeId = String.valueOf(this.util.getUserId()) + RandomUtil.randomInt(100, 1000) + Instant.now().getEpochSecond(); 200 | String name = "充值" + point + "余额-" + tradeId; 201 | double money = (double) point / Special.moneyPointProportion; 202 | YiPayType payType = switch (type) { 203 | case "ali" -> YiPayType.ALI; 204 | case "wechat" -> YiPayType.WECHAT; 205 | default -> YiPayType.ALI; 206 | }; 207 | 208 | YiPayResponse response; 209 | try { 210 | response = YiPay.pay(platformId, merchantPrivateKey, noticeUrlPrefix + "common/yi_pay_callback", returnUrl, tradeId, name, money, payType, this.request.getHeader("X-Real-IP") == null ? request.getRemoteAddr() : this.request.getHeader("X-Real-IP")); 211 | if (response.getCode() != 0) { 212 | throw new IOException(); 213 | } 214 | } catch (IOException error) { 215 | throw new ExceptionResponse(ExceptionResponseCode.RUN_ERROR, "充值失败"); 216 | } 217 | 218 | Recharge recharge = new Recharge(); 219 | recharge.setId(tradeId); 220 | recharge.setPoint(point); 221 | recharge.setMoney(BigDecimal.valueOf(money)); 222 | recharge.setUrl(response.getPay_info()); 223 | recharge.setUserId(this.util.getUserId()); 224 | this.recharge.insert(recharge); 225 | return new GenerateResponse<>(response.getPay_info()); 226 | } 227 | 228 | public GenerateResponse> getRecharge(GetRechargeParameter parameter) { 229 | int pageSize = parameter.getPageSize(); 230 | int pageNumber = parameter.getPageNumber(); 231 | 232 | LambdaQueryWrapper wrapper = new LambdaQueryWrapper<>(); 233 | wrapper.eq(Recharge::getUserId, this.util.getUserId()); 234 | wrapper.orderByDesc(Recharge::getCreationTime); 235 | Page page = new Page<>(); 236 | page.setSize(pageSize); 237 | page.setCurrent(pageNumber); 238 | 239 | Page data = this.recharge.selectPage(page, wrapper); 240 | List> results = data.getRecords().stream().map(item -> { 241 | Map result = new HashMap<>(Map.of( 242 | "id", item.getId(), 243 | "point", item.getPoint(), 244 | "money", item.getMoney(), 245 | "url", item.getUrl(), 246 | "state", item.isState(), 247 | "creationTime", Auxiliary.localDateTimeToTimestamp(item.getCreationTime()) 248 | )); 249 | result.put("paymentTime", item.getPaymentTime() == null ? null : Auxiliary.localDateTimeToTimestamp(item.getPaymentTime())); 250 | return result; 251 | }).toList(); 252 | return new GenerateResponse<>(Map.of( 253 | "data", results, 254 | "total", data.getTotal() 255 | )); 256 | } 257 | 258 | public GenerateResponse> getRecord(GetRecordParameter parameter) { 259 | int toolId = parameter.getToolId(); 260 | int pageSize = parameter.getPageSize(); 261 | int pageNumber = parameter.getPageNumber(); 262 | 263 | if (this.tool.selectById(toolId) == null) { 264 | throw new ExceptionResponse(ExceptionResponseCode.PARAMETER_ERROR, "工具ID不存在"); 265 | } 266 | 267 | LambdaQueryWrapper wrapper = new LambdaQueryWrapper<>(); 268 | wrapper.eq(Record::getToolId, toolId); 269 | wrapper.eq(Record::getUserId, this.util.getUserId()); 270 | wrapper.orderByDesc(Record::getTime); 271 | Page page = new Page<>(); 272 | page.setSize(pageSize); 273 | page.setCurrent(pageNumber); 274 | 275 | Page data = this.record.selectPage(page, wrapper); 276 | List> results = data.getRecords().stream().map(item -> { 277 | return Map.of( 278 | "id", item.getId(), 279 | "request", item.getRequest(), 280 | "response", item.getResponse(), 281 | "time", Auxiliary.localDateTimeToTimestamp(item.getTime()) 282 | ); 283 | }).toList(); 284 | return new GenerateResponse<>(Map.of( 285 | "data", results, 286 | "total", data.getTotal() 287 | )); 288 | } 289 | 290 | public GenerateResponse useCard(UseCardParameter parameter) { 291 | String code = parameter.getCode(); 292 | 293 | LambdaQueryWrapper cardWrapper = new LambdaQueryWrapper<>(); 294 | cardWrapper.eq(Card::getCode, code); 295 | Card card = this.card.selectOne(cardWrapper); 296 | if (card == null) { 297 | throw new ExceptionResponse(ExceptionResponseCode.PARAMETER_ERROR, "码不存在"); 298 | } else if (card.getCount() >= card.getNumber()) { 299 | throw new ExceptionResponse(ExceptionResponseCode.USER_ERROR, "已被兑换完"); 300 | } 301 | 302 | LambdaQueryWrapper cardRecordWrapper = new LambdaQueryWrapper<>(); 303 | cardRecordWrapper.eq(CardRecord::getCardId, card.getId()); 304 | cardRecordWrapper.eq(CardRecord::getUserId, this.util.getUserId()); 305 | if (this.cardRecord.exists(cardRecordWrapper)) { 306 | throw new ExceptionResponse(ExceptionResponseCode.USER_ERROR, "已兑换"); 307 | } 308 | 309 | CardRecord cardRecord = new CardRecord(); 310 | cardRecord.setCardId(card.getId()); 311 | cardRecord.setUserId(this.util.getUserId()); 312 | this.cardRecord.insert(cardRecord); 313 | 314 | card.setCount(card.getCount() + 1); 315 | this.card.updateById(card); 316 | 317 | User user = this.user.selectById(this.util.getUserId()); 318 | user.setRewardBalance(user.getRewardBalance() + card.getPoint()); 319 | this.user.updateById(user); 320 | return new GenerateResponse<>(card.getPoint()); 321 | } 322 | } -------------------------------------------------------------------------------- /src/main/java/fun/diviner/aidiviner/service/UtilService.java: -------------------------------------------------------------------------------- 1 | package fun.diviner.aidiviner.service; 2 | 3 | import java.util.UUID; 4 | 5 | import org.springframework.stereotype.Service; 6 | import org.springframework.beans.factory.annotation.Autowired; 7 | import org.springframework.web.context.request.RequestContextHolder; 8 | import org.springframework.web.context.request.ServletRequestAttributes; 9 | import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; 10 | 11 | import fun.diviner.aidiviner.mapper.CoreMapper; 12 | import fun.diviner.aidiviner.mapper.UserMapper; 13 | import fun.diviner.aidiviner.mapper.RecordMapper; 14 | import fun.diviner.aidiviner.entity.Auth; 15 | import fun.diviner.aidiviner.entity.Special; 16 | import fun.diviner.aidiviner.entity.PayType; 17 | import fun.diviner.aidiviner.entity.Pay; 18 | import fun.diviner.aidiviner.entity.Trade; 19 | import fun.diviner.aidiviner.entity.database.Core; 20 | import fun.diviner.aidiviner.entity.database.User; 21 | import fun.diviner.aidiviner.entity.database.Record; 22 | 23 | @Service 24 | public class UtilService { 25 | @Autowired 26 | private CoreMapper core; 27 | @Autowired 28 | private UserMapper user; 29 | @Autowired 30 | private RecordMapper record; 31 | 32 | public void setAttribute(String key, T value) { 33 | RequestContextHolder.currentRequestAttributes().setAttribute(key, value, ServletRequestAttributes.SCOPE_REQUEST); 34 | } 35 | 36 | public T getAttribute(String key) { 37 | return (T) RequestContextHolder.currentRequestAttributes().getAttribute(key, ServletRequestAttributes.SCOPE_REQUEST); 38 | } 39 | 40 | public int getUserId() { 41 | return ((Auth) this.getAttribute(Special.AttributeName.user)).getId(); 42 | } 43 | 44 | public String getCoreContent(String name) { 45 | LambdaQueryWrapper wrapper = new LambdaQueryWrapper<>(); 46 | wrapper.eq(Core::getName, name); 47 | return this.core.selectOne(wrapper).getContent(); 48 | } 49 | 50 | public Pay pay(PayType type, int price) { 51 | Pay pay = new Pay(); 52 | if (price == 0) { 53 | pay.setType(PayType.FREE); 54 | } else { 55 | pay.setType(type); 56 | User user = this.user.selectById(this.getUserId()); 57 | switch (type) { 58 | case RECHARGE_BALANCE -> { 59 | if (price > user.getRechargeBalance()) { 60 | return pay; 61 | } 62 | 63 | pay.setRecharge(price); 64 | user.setRechargeBalance(user.getRechargeBalance() - price); 65 | } 66 | case BALANCE -> { 67 | if (price <= user.getRewardBalance()) { 68 | pay.setReward(price); 69 | user.setRewardBalance(user.getRewardBalance() - price); 70 | } else { 71 | int miss = price - user.getRewardBalance(); 72 | if (miss > user.getRechargeBalance()) { 73 | return pay; 74 | } 75 | 76 | pay.setReward(user.getRewardBalance()); 77 | pay.setRecharge(miss); 78 | user.setRewardBalance(0); 79 | user.setRechargeBalance(user.getRechargeBalance() - miss); 80 | } 81 | } 82 | } 83 | this.user.updateById(user); 84 | } 85 | pay.setState(true); 86 | return pay; 87 | } 88 | 89 | public void refund() { 90 | Pay pay = ((Trade) this.getAttribute(Special.AttributeName.trade)).getPay(); 91 | if (pay.getType() == PayType.FREE) { 92 | return; 93 | } 94 | 95 | User user = this.user.selectById(this.getUserId()); 96 | switch (pay.getType()) { 97 | case RECHARGE_BALANCE -> { 98 | user.setRechargeBalance(user.getRechargeBalance() + pay.getRecharge()); 99 | } 100 | case BALANCE -> { 101 | user.setRewardBalance(user.getRewardBalance() + pay.getReward()); 102 | user.setRechargeBalance(user.getRechargeBalance() + pay.getRecharge()); 103 | } 104 | } 105 | this.user.updateById(user); 106 | } 107 | 108 | public void record(String request, String response) { 109 | Record record = new Record(); 110 | record.setId(UUID.randomUUID().toString()); 111 | record.setToolId(((Trade) this.getAttribute(Special.AttributeName.trade)).getId()); 112 | record.setRequest(request); 113 | record.setResponse(response); 114 | record.setUserId(this.getUserId()); 115 | this.record.insert(record); 116 | } 117 | } -------------------------------------------------------------------------------- /src/main/java/fun/diviner/aidiviner/service/tool/BaZiService.java: -------------------------------------------------------------------------------- 1 | package fun.diviner.aidiviner.service.tool; 2 | 3 | import java.util.List; 4 | 5 | import org.springframework.beans.factory.annotation.Autowired; 6 | import org.springframework.stereotype.Service; 7 | 8 | import fun.diviner.aidiviner.diviner.BaZi; 9 | import fun.diviner.aidiviner.diviner.bazi.BaZiTool; 10 | import fun.diviner.aidiviner.diviner.type.BaZiArrangeItem; 11 | import fun.diviner.aidiviner.diviner.type.BaZiArrangeResponse; 12 | import fun.diviner.aidiviner.dto.tool.bazi.BaZiArrangeParameter; 13 | import fun.diviner.aidiviner.dto.tool.bazi.BaZiSolveParameter; 14 | import fun.diviner.aidiviner.service.UtilService; 15 | import fun.diviner.aidiviner.util.response.ExceptionResponse; 16 | import fun.diviner.aidiviner.util.response.ExceptionResponseCode; 17 | import fun.diviner.aidiviner.util.response.GenerateResponse; 18 | 19 | /** 20 | * @author Coaixy 21 | * @createTime 2025-01-23 22 | * @packageName fun.diviner.service.tool 23 | **/ 24 | 25 | @Service 26 | public class BaZiService { 27 | @Autowired 28 | private UtilService util; 29 | 30 | public GenerateResponse arrange(BaZiArrangeParameter parameter) { 31 | return new GenerateResponse<>(generateBaZiResponse(BaZi.getBaZiObj(parameter))); 32 | } 33 | 34 | /** 35 | * 返回八字分析结果 36 | * 37 | * @param obj Bazi对象 38 | * @return BaziResponse 39 | */ 40 | private BaZiArrangeResponse generateBaZiResponse(BaZiTool obj) { 41 | BaZiArrangeResponse response = new BaZiArrangeResponse(); 42 | //year 43 | BaZiArrangeItem yearItem = new BaZiArrangeItem("年柱", obj.getYearGan(), obj.getYearZhi(), obj.getYearZhiCangGan(), obj.getYearGanZhiZhuXing(), obj.getYearGanZhiFuXing()); 44 | //month 45 | BaZiArrangeItem monthItem = new BaZiArrangeItem("月柱", obj.getMonthGan(), obj.getMonthZhi(), obj.getMonthZhiCangGan(), obj.getMonthGanZhiZhuXing(), obj.getMonthGanZhiFuXing()); 46 | //day 47 | BaZiArrangeItem dayItem = new BaZiArrangeItem("日柱", obj.getDayGan(), obj.getDayZhi(), obj.getDayZhiCangGan(), obj.getDayGanZhiZhuXing(), obj.getDayGanZhiFuXing()); 48 | //hour 49 | BaZiArrangeItem hourItem = new BaZiArrangeItem("时柱", obj.getHourGan(), obj.getHourZhi(), obj.getHourZhiCangGan(), obj.getHourGanZhiZhuXing(), obj.getHourGanZhiFuXing()); 50 | 51 | response.setYearPillar(yearItem); 52 | response.setMonthPillar(monthItem); 53 | response.setDayPillar(dayItem); 54 | response.setHourPillar(hourItem); 55 | 56 | response.setBaZiWuXingCount(obj.getBaZiWuXingCount()); 57 | response.setBaZiwuXingWangShuai(obj.getWuXingWangShuai()); 58 | response.setBodyIntensity(obj.getBodyIntensity()); 59 | response.setGuZhong(obj.getGuZhong()); 60 | response.setGuZhongPiZhu(obj.getGuZhongPiZhu()); 61 | response.setDayZhuLunMing(obj.getDayZhuLunMing()); 62 | response.setYinYuan(obj.getYinYuan()); 63 | response.setWuXingFenXi(obj.getWuXingFenXi()); 64 | List> daYun = obj.getDaYun(); 65 | daYun.get(0).set(2, obj.getXiaoYun().get(0).get(2)); 66 | response.setDayun(daYun); 67 | response.setLiuNian(obj.getLiuNian()); 68 | 69 | return response; 70 | } 71 | 72 | public GenerateResponse solve(BaZiSolveParameter parameter) { 73 | try { 74 | String response = BaZi.getAIResponse(parameter); 75 | 76 | // 防止返回空,以后可以去掉 77 | if (response == null || response.isEmpty()) { 78 | throw new Exception(); 79 | } 80 | 81 | if (parameter.getDayun().isEmpty()) { 82 | this.util.record(parameter.getBazi(), response); 83 | } else { 84 | this.util.record(parameter.getBazi() + "\n大运:" + parameter.getDayun() + " 流年:"+ parameter.getLiunian(), response); 85 | } 86 | return new GenerateResponse<>(response); 87 | } catch (Exception error) { 88 | this.util.refund(); 89 | throw new ExceptionResponse(ExceptionResponseCode.RUN_ERROR, "回答出错"); 90 | } 91 | } 92 | } -------------------------------------------------------------------------------- /src/main/java/fun/diviner/aidiviner/service/tool/MeiHuaService.java: -------------------------------------------------------------------------------- 1 | package fun.diviner.aidiviner.service.tool; 2 | 3 | import java.util.Date; 4 | 5 | import cn.hutool.core.util.RandomUtil; 6 | import org.springframework.beans.factory.annotation.Autowired; 7 | import org.springframework.stereotype.Service; 8 | 9 | import fun.diviner.aidiviner.diviner.MeiHua; 10 | import fun.diviner.aidiviner.diviner.meihua.MeiHuaObj; 11 | import fun.diviner.aidiviner.diviner.meihua.MeiHuaSetting; 12 | import fun.diviner.aidiviner.diviner.type.MeiHuaArrangeResponse; 13 | import fun.diviner.aidiviner.diviner.type.MeiHuaGuaItem; 14 | import fun.diviner.aidiviner.dto.tool.meihua.MeiHuaArrangeParameter; 15 | import fun.diviner.aidiviner.dto.tool.meihua.MeiHuaSolveParameter; 16 | import fun.diviner.aidiviner.service.UtilService; 17 | import fun.diviner.aidiviner.util.response.GenerateResponse; 18 | 19 | /** 20 | * @author Coaixy 21 | * @createTime 2025-01-25 22 | * @packageName fun.diviner.service.tool 23 | **/ 24 | 25 | @Service 26 | public class MeiHuaService { 27 | @Autowired 28 | private UtilService util; 29 | 30 | public GenerateResponse arrange(MeiHuaArrangeParameter parameter) { 31 | MeiHuaObj meiHuaObj; 32 | String type = parameter.getType(); 33 | if (type.equalsIgnoreCase("time")) { 34 | meiHuaObj = new MeiHuaObj(new Date()); 35 | } else if (type.equalsIgnoreCase("number")) { 36 | meiHuaObj = numberToMeiHuaObj(parameter.getNumber()); 37 | } else { 38 | meiHuaObj = numberToMeiHuaObj(RandomUtil.randomInt(10, 2147483647)); 39 | } 40 | MeiHuaArrangeResponse response = new MeiHuaArrangeResponse(); 41 | response.setBazi(meiHuaObj.getBaZi()); 42 | //本卦 43 | MeiHuaGuaItem ben = new MeiHuaGuaItem(); 44 | ben.setName(meiHuaObj.getBenGua()); 45 | ben.setGuaci(meiHuaObj.getBenGuaGuaCi()); 46 | ben.setYao(meiHuaObj.getBenGuaLiuYaoAs()); 47 | ben.setShanggua(meiHuaObj.getBenGuaShangGua()); 48 | ben.setXiagua(meiHuaObj.getBenGuaXiaGua()); 49 | response.setBen(ben); 50 | // 互卦 51 | MeiHuaGuaItem hu = new MeiHuaGuaItem(); 52 | hu.setName(meiHuaObj.getHuGua()); 53 | hu.setGuaci(meiHuaObj.getHuGuaGuaCi()); 54 | hu.setYao(meiHuaObj.getHuGuaLiuYaoAs()); 55 | hu.setShanggua(meiHuaObj.getHuGuaShangGua()); 56 | hu.setXiagua(meiHuaObj.getHuGuaXiaGua()); 57 | response.setHu(hu); 58 | // 变卦 59 | MeiHuaGuaItem bian = new MeiHuaGuaItem(); 60 | bian.setName(meiHuaObj.getBianGua()); 61 | bian.setGuaci(meiHuaObj.getBianGuaGuaCi()); 62 | bian.setYao(meiHuaObj.getBianGuaLiuYaoAs()); 63 | bian.setShanggua(meiHuaObj.getBianGuaShangGua()); 64 | bian.setXiagua(meiHuaObj.getBianGuaXiaGua()); 65 | response.setBian(bian); 66 | response.setDong(7 - meiHuaObj.getDongYaoNumber()); 67 | 68 | return new GenerateResponse<>(response); 69 | 70 | } 71 | 72 | private MeiHuaObj numberToMeiHuaObj(int number) { 73 | 74 | MeiHuaSetting meiHuaSetting = new MeiHuaSetting(); 75 | //数字起卦 76 | meiHuaSetting.setQiGuaMode(2); 77 | meiHuaSetting.setQiGuaDanNumber(number); 78 | return new MeiHuaObj(meiHuaSetting); 79 | } 80 | 81 | public GenerateResponse solve(MeiHuaSolveParameter parameter) { 82 | try { 83 | String response = MeiHua.getAIResponse(parameter.getArrangeResponse(), parameter.getQuestion()); 84 | 85 | // 防止返回空,以后可以去掉 86 | if (response == null || response.isEmpty()) { 87 | throw new Exception(); 88 | } 89 | 90 | this.util.record(parameter.getQuestion(), response); 91 | return new GenerateResponse<>(response); 92 | } catch (Exception error) { 93 | this.util.refund(); 94 | return new GenerateResponse<>("解卦出错"); 95 | } 96 | } 97 | } -------------------------------------------------------------------------------- /src/main/java/fun/diviner/aidiviner/service/tool/TarotService.java: -------------------------------------------------------------------------------- 1 | package fun.diviner.aidiviner.service.tool; 2 | 3 | import org.springframework.beans.factory.annotation.Autowired; 4 | import org.springframework.stereotype.Service; 5 | 6 | import fun.diviner.aidiviner.diviner.Tarot; 7 | import fun.diviner.aidiviner.diviner.type.TarotResponse; 8 | import fun.diviner.aidiviner.dto.tool.tarot.TarotCommonParameter; 9 | import fun.diviner.aidiviner.dto.tool.tarot.TarotSelectParameter; 10 | import fun.diviner.aidiviner.service.UtilService; 11 | import fun.diviner.aidiviner.util.response.ExceptionResponse; 12 | import fun.diviner.aidiviner.util.response.ExceptionResponseCode; 13 | import fun.diviner.aidiviner.util.response.GenerateResponse; 14 | 15 | /** 16 | * @author Coaixy 17 | * @createTime 2025-01-24 18 | * @packageName fun.diviner.service.tool 19 | **/ 20 | 21 | @Service 22 | public class TarotService { 23 | @Autowired 24 | private Tarot tarot; 25 | @Autowired 26 | private UtilService util; 27 | 28 | public GenerateResponse common(TarotCommonParameter parameter, boolean isPro) { 29 | try { 30 | String question = parameter.getQuestion(); 31 | String spread = this.tarot.getTarotSpread(question); 32 | spread = formatSpreadName(spread); 33 | int needNum = this.tarot.getTarotNeedNum(spread); 34 | TarotResponse result = this.tarot.getTarotAnswer(question, spread, needNum, isPro); 35 | 36 | // 防止返回空,以后可以去掉 37 | if (result.getAnswer() == null || result.getAnswer().isEmpty()) { 38 | throw new Exception(); 39 | } 40 | 41 | this.util.record(question, result.getAnswer()); 42 | return new GenerateResponse<>(result); 43 | } catch (Exception error) { 44 | this.util.refund(); 45 | throw new ExceptionResponse(ExceptionResponseCode.RUN_ERROR, "这个问题我不能回答你"); 46 | } 47 | } 48 | 49 | private String formatSpreadName(String spreadName) { 50 | if (spreadName.equals("foundations")) { 51 | return "foundation"; 52 | } 53 | if (spreadName.contains(":")) { 54 | return spreadName.split(":")[1]; 55 | } 56 | if (spreadName.contains(":")) { 57 | return spreadName.split(":")[1]; 58 | } 59 | return spreadName; 60 | } 61 | 62 | public GenerateResponse select(TarotSelectParameter parameter, boolean isPro) { 63 | try { 64 | TarotResponse result = this.tarot.getTarotAnswerBySelectIndex(parameter.getQuestion(), parameter.getSpreadName(), parameter.getCardIndexList(), isPro); 65 | 66 | // 防止返回空,以后可以去掉 67 | if (result.getAnswer() == null || result.getAnswer().isEmpty()) { 68 | throw new Exception(); 69 | } 70 | 71 | this.util.record(parameter.getQuestion(), result.getAnswer()); 72 | return new GenerateResponse<>(result); 73 | } catch (Exception error) { 74 | this.util.refund(); 75 | throw new ExceptionResponse(ExceptionResponseCode.RUN_ERROR, "回答出错"); 76 | } 77 | } 78 | } -------------------------------------------------------------------------------- /src/main/java/fun/diviner/aidiviner/util/Auxiliary.java: -------------------------------------------------------------------------------- 1 | package fun.diviner.aidiviner.util; 2 | 3 | import java.time.LocalDateTime; 4 | import java.time.ZoneId; 5 | 6 | public class Auxiliary { 7 | public static long localDateTimeToTimestamp(LocalDateTime time) { 8 | ZoneId zone = ZoneId.systemDefault(); 9 | return time.atZone(zone).toInstant().getEpochSecond(); 10 | } 11 | } -------------------------------------------------------------------------------- /src/main/java/fun/diviner/aidiviner/util/response/ExceptionResponse.java: -------------------------------------------------------------------------------- 1 | package fun.diviner.aidiviner.util.response; 2 | 3 | import lombok.Getter; 4 | 5 | @Getter 6 | public class ExceptionResponse extends RuntimeException { 7 | private ExceptionResponseCode code; 8 | 9 | public ExceptionResponse(ExceptionResponseCode code, String message) { 10 | super(message); 11 | this.code = code; 12 | } 13 | } -------------------------------------------------------------------------------- /src/main/java/fun/diviner/aidiviner/util/response/ExceptionResponseCode.java: -------------------------------------------------------------------------------- 1 | package fun.diviner.aidiviner.util.response; 2 | 3 | import lombok.Getter; 4 | 5 | @Getter 6 | public enum ExceptionResponseCode { 7 | PARAMETER_ERROR(110), 8 | USER_ERROR(120), 9 | RUN_ERROR(130); 10 | 11 | private int code; 12 | 13 | ExceptionResponseCode(int code) { 14 | this.code = code; 15 | } 16 | } -------------------------------------------------------------------------------- /src/main/java/fun/diviner/aidiviner/util/response/GenerateResponse.java: -------------------------------------------------------------------------------- 1 | package fun.diviner.aidiviner.util.response; 2 | 3 | import lombok.Getter; 4 | 5 | @Getter 6 | public class GenerateResponse { 7 | private int code; 8 | private String message; 9 | private T data; 10 | 11 | public GenerateResponse(int code, String message){ 12 | this.code = code; 13 | this.message = message; 14 | } 15 | 16 | public GenerateResponse(T data){ 17 | this.code = 200; 18 | this.message = "success"; 19 | this.data = data; 20 | } 21 | } -------------------------------------------------------------------------------- /src/main/java/fun/diviner/aidiviner/util/yi_pay/YiPay.java: -------------------------------------------------------------------------------- 1 | package fun.diviner.aidiviner.util.yi_pay; 2 | 3 | import java.util.Map; 4 | import java.util.StringJoiner; 5 | import java.util.TreeMap; 6 | import java.util.HashMap; 7 | import java.io.IOException; 8 | import java.time.Instant; 9 | 10 | import cn.hutool.crypto.asymmetric.Sign; 11 | import cn.hutool.crypto.asymmetric.SignAlgorithm; 12 | import cn.hutool.crypto.SecureUtil; 13 | import cn.hutool.core.codec.Base64; 14 | import okhttp3.FormBody; 15 | import okhttp3.Request; 16 | import okhttp3.Response; 17 | import okhttp3.OkHttpClient; 18 | import com.fasterxml.jackson.databind.ObjectMapper; 19 | 20 | public class YiPay { 21 | private static String getSignData(Map data) { 22 | StringJoiner result = new StringJoiner("&"); 23 | Map sort = new TreeMap<>(data); 24 | for (Map.Entry item: sort.entrySet()) { 25 | if (!item.getValue().isEmpty()) { 26 | result.add(item.getKey() + "=" + item.getValue()); 27 | } 28 | } 29 | return result.toString(); 30 | } 31 | 32 | public static YiPayResponse pay(int platformId, String merchantPrivateKey, String notifyUrl, String returnUrl, String tradeId, String name, double money, YiPayType type, String ipAddress) throws IOException { 33 | Map data = new HashMap<>(); 34 | data.put("pid", String.valueOf(platformId)); 35 | data.put("method", "jump"); 36 | data.put("type", type.getValue()); 37 | data.put("out_trade_no", tradeId); 38 | data.put("notify_url", notifyUrl); 39 | data.put("return_url", returnUrl); 40 | data.put("name", name); 41 | data.put("money", String.valueOf(money)); 42 | data.put("clientip", ipAddress); 43 | data.put("timestamp", String.valueOf(Instant.now().getEpochSecond())); 44 | 45 | String signData = YiPay.getSignData(data); 46 | Sign signUtil = SecureUtil.sign(SignAlgorithm.SHA256withRSA, merchantPrivateKey, null); 47 | data.put("sign", Base64.encode(signUtil.sign(signData))); 48 | data.put("sign_type", "RSA"); 49 | FormBody.Builder postData = new FormBody.Builder(); 50 | data.forEach(postData::add); 51 | 52 | Request request = new Request.Builder().url("https://yi-pay.com/api/pay/create").post(postData.build()).build(); 53 | try (Response response = new OkHttpClient().newCall(request).execute()) { 54 | return new ObjectMapper().readValue(response.body().string(), YiPayResponse.class); 55 | } 56 | } 57 | 58 | public static boolean verify(String platformPublicKey, Map data) { 59 | Sign signUtil = SecureUtil.sign(SignAlgorithm.SHA256withRSA, null, platformPublicKey); 60 | String sign = data.remove("sign"); 61 | data.remove("sign_type"); 62 | return signUtil.verify(YiPay.getSignData(data).getBytes(), Base64.decode(sign)); 63 | } 64 | } -------------------------------------------------------------------------------- /src/main/java/fun/diviner/aidiviner/util/yi_pay/YiPayResponse.java: -------------------------------------------------------------------------------- 1 | package fun.diviner.aidiviner.util.yi_pay; 2 | 3 | import lombok.Data; 4 | 5 | @Data 6 | public class YiPayResponse { 7 | private int code; 8 | private String msg; 9 | private String trade_no; 10 | private String pay_type; 11 | private String pay_info; 12 | private String timestamp; 13 | private String sign_type; 14 | private String sign; 15 | } -------------------------------------------------------------------------------- /src/main/java/fun/diviner/aidiviner/util/yi_pay/YiPayType.java: -------------------------------------------------------------------------------- 1 | package fun.diviner.aidiviner.util.yi_pay; 2 | 3 | public enum YiPayType { 4 | ALI("alipay"), 5 | WECHAT("wxpay"); 6 | 7 | private String type; 8 | 9 | YiPayType(String type) { 10 | this.type = type; 11 | } 12 | 13 | public String getValue() { 14 | return this.type; 15 | } 16 | } -------------------------------------------------------------------------------- /src/main/resources/application.yml: -------------------------------------------------------------------------------- 1 | spring: 2 | datasource: 3 | url: jdbc:mysql://127.0.0.1/ai_diviner 4 | username: root 5 | password: root 6 | data: 7 | redis: 8 | host: 127.0.0.1 9 | password: root 10 | web: 11 | resources: 12 | add-mappings: false 13 | 14 | server: 15 | port: 232 16 | servlet: 17 | encoding: 18 | force: true --------------------------------------------------------------------------------