diff --git a/win-module-eam/win-module-eam-api/src/main/java/com/win/module/eam/enums/ErrorCodeConstants.java b/win-module-eam/win-module-eam-api/src/main/java/com/win/module/eam/enums/ErrorCodeConstants.java index f3d7898..ebf65ec 100644 --- a/win-module-eam/win-module-eam-api/src/main/java/com/win/module/eam/enums/ErrorCodeConstants.java +++ b/win-module-eam/win-module-eam-api/src/main/java/com/win/module/eam/enums/ErrorCodeConstants.java @@ -167,6 +167,6 @@ public interface ErrorCodeConstants { ErrorCode LOCATION_EXISTS = new ErrorCode(1_000_020_021, "该库位已与备件绑定不可重复绑定"); ErrorCode ITEM_EXISTS = new ErrorCode(1_000_020_021, "该备件已绑定不可重复绑定"); - + ErrorCode ENCRYPTION_STR_FORMAT_IS_ERROR = new ErrorCode(1_000_020_064, "授权码字符串格式错误"); } diff --git a/win-module-eam/win-module-eam-biz/pom.xml b/win-module-eam/win-module-eam-biz/pom.xml index a501a4f..77d6dbd 100644 --- a/win-module-eam/win-module-eam-biz/pom.xml +++ b/win-module-eam/win-module-eam-biz/pom.xml @@ -124,6 +124,12 @@ com.alibaba fastjson + + com.google.zxing + core + 3.3.1 + compile + diff --git a/win-module-eam/win-module-eam-biz/src/main/java/com/win/module/eam/controller/licences/LicencesController.java b/win-module-eam/win-module-eam-biz/src/main/java/com/win/module/eam/controller/licences/LicencesController.java new file mode 100644 index 0000000..204a31a --- /dev/null +++ b/win-module-eam/win-module-eam-biz/src/main/java/com/win/module/eam/controller/licences/LicencesController.java @@ -0,0 +1,59 @@ +package com.win.module.eam.controller.licences; + +import cn.hutool.extra.qrcode.QrCodeUtil; +import com.win.framework.common.pojo.CommonResult; +import com.win.module.eam.controller.licences.vo.GenerateLicenceReqVO; +import com.win.module.eam.service.licences.LicencesService; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.Parameter; +import io.swagger.v3.oas.annotations.Parameters; +import io.swagger.v3.oas.annotations.tags.Tag; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.*; +import org.springframework.web.multipart.MultipartFile; + +import javax.annotation.Resource; +import javax.servlet.http.HttpServletResponse; +import javax.validation.Valid; +import javax.validation.constraints.NotNull; +import java.io.IOException; + +import static com.win.framework.common.pojo.CommonResult.success; + +@Tag(name = "接口-续期许可") +@RestController +@RequestMapping("/eam/basic/licences") +@Validated +public class LicencesController { + @Resource + private LicencesService licencesService; + + @PostMapping("/licenceDiscernByCodeFile") + @Operation(summary = "识别续期许可(二维码图片)") + @Parameters({ + @Parameter(name = "file", description = "续期二维码图片", required = true) + }) + @PreAuthorize("@ss.hasPermission('basic:licences:licenceDiscern')") + public CommonResult licenceDiscernByCodeFile(@Valid @NotNull @RequestParam("file") MultipartFile file) throws IOException { + licencesService.licencesDiscern(QrCodeUtil.decode(file.getInputStream())); + return success(true); + } + + @PostMapping("/licenceDiscernByCodeStr") + @Operation(summary = "识别续期许可(二维码字符串)") + @Parameters({ + @Parameter(name = "code", description = "续期二维码识别出来的字符串", required = true) + }) + @PreAuthorize("@ss.hasPermission('basic:licences:licenceDiscern')") + public CommonResult licenceDiscernByCodeStr(@RequestBody String code) { + licencesService.licencesDiscern(code); + return success(true); + } + @PostMapping("/generateLicence") + @Operation(summary = "生成续期二维码") + @PreAuthorize("@ss.hasPermission('basic:licences:licenceDiscern')") + public void generateLicence(@Valid @RequestBody GenerateLicenceReqVO req,HttpServletResponse response) throws Exception { + licencesService.generateLicence(req,response); + } +} diff --git a/win-module-eam/win-module-eam-biz/src/main/java/com/win/module/eam/controller/licences/vo/GenerateLicenceReqVO.java b/win-module-eam/win-module-eam-biz/src/main/java/com/win/module/eam/controller/licences/vo/GenerateLicenceReqVO.java new file mode 100644 index 0000000..693728d --- /dev/null +++ b/win-module-eam/win-module-eam-biz/src/main/java/com/win/module/eam/controller/licences/vo/GenerateLicenceReqVO.java @@ -0,0 +1,20 @@ +package com.win.module.eam.controller.licences.vo; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.ToString; + +import javax.validation.constraints.NotNull; + +@Schema(description = "管理后台 - 生成续期码 Request VO") +@Data +@ToString(callSuper = true) +public class GenerateLicenceReqVO { + @NotNull(message = "公司编码不能为空") + @Schema(description = "公司编码") + private String companyCode; + + @NotNull(message = "到期时间不能为空") + @Schema(description = "到期时间") + private String endTime; +} diff --git a/win-module-eam/win-module-eam-biz/src/main/java/com/win/module/eam/mq/message/LicencesMessage.java b/win-module-eam/win-module-eam-biz/src/main/java/com/win/module/eam/mq/message/LicencesMessage.java new file mode 100644 index 0000000..15ba2db --- /dev/null +++ b/win-module-eam/win-module-eam-biz/src/main/java/com/win/module/eam/mq/message/LicencesMessage.java @@ -0,0 +1,13 @@ +package com.win.module.eam.mq.message; + +import lombok.Data; +import lombok.ToString; + +import java.util.List; + +@Data +@ToString(callSuper = true) +public class LicencesMessage { + private String secretKey; + private String data; +} diff --git a/win-module-eam/win-module-eam-biz/src/main/java/com/win/module/eam/service/licences/LicencesService.java b/win-module-eam/win-module-eam-biz/src/main/java/com/win/module/eam/service/licences/LicencesService.java new file mode 100644 index 0000000..68f9eb2 --- /dev/null +++ b/win-module-eam/win-module-eam-biz/src/main/java/com/win/module/eam/service/licences/LicencesService.java @@ -0,0 +1,11 @@ +package com.win.module.eam.service.licences; + +import com.win.module.eam.controller.licences.vo.GenerateLicenceReqVO; + +import javax.servlet.http.HttpServletResponse; +import javax.validation.Valid; + +public interface LicencesService { + void licencesDiscern(String encryptionStr); + void generateLicence(@Valid GenerateLicenceReqVO req, HttpServletResponse response) throws Exception; +} \ No newline at end of file diff --git a/win-module-eam/win-module-eam-biz/src/main/java/com/win/module/eam/service/licences/LicencesServiceImpl.java b/win-module-eam/win-module-eam-biz/src/main/java/com/win/module/eam/service/licences/LicencesServiceImpl.java new file mode 100644 index 0000000..ebb1fd1 --- /dev/null +++ b/win-module-eam/win-module-eam-biz/src/main/java/com/win/module/eam/service/licences/LicencesServiceImpl.java @@ -0,0 +1,108 @@ +package com.win.module.eam.service.licences; + +import cn.hutool.core.codec.Base64; +import cn.hutool.crypto.digest.MD5; +import cn.hutool.extra.qrcode.QrCodeUtil; +import cn.hutool.extra.qrcode.QrConfig; +import com.alibaba.excel.metadata.data.ImageData; +import com.alibaba.fastjson.JSONArray; +import com.alibaba.fastjson.JSONObject; +import com.win.module.eam.controller.licences.vo.GenerateLicenceReqVO; +import com.win.module.eam.mq.message.LicencesMessage; +import org.apache.calcite.util.Util; +import org.springframework.data.redis.core.RedisTemplate; +import org.springframework.stereotype.Service; + +import javax.annotation.Resource; +import javax.crypto.Cipher; +import javax.crypto.KeyGenerator; +import javax.crypto.SecretKey; +import javax.crypto.spec.SecretKeySpec; +import javax.servlet.http.HttpServletResponse; +import java.nio.charset.StandardCharsets; +import java.util.ArrayList; +import java.util.List; + +import static com.win.framework.common.exception.util.ServiceExceptionUtil.exception; +import static com.win.module.eam.enums.ErrorCodeConstants.ENCRYPTION_STR_FORMAT_IS_ERROR; + +@Service +public class LicencesServiceImpl implements LicencesService { + private static final String ALGORITHM = "AES"; + private static final int KEY_SIZE = 128; + private static final String LICENCES_UPDATE = "LICENCES"; + @Resource + private RedisTemplate redisTemplate; + + private static String generateKey() throws Exception { + KeyGenerator keyGenerator = KeyGenerator.getInstance(ALGORITHM); + keyGenerator.init(KEY_SIZE); + SecretKey secretKey = keyGenerator.generateKey(); + return Base64.encode(secretKey.getEncoded()); + } + + private static String encrypt(String data, String key) throws Exception { + SecretKeySpec secretKeySpec = new SecretKeySpec(Base64.decode(key), ALGORITHM); + Cipher cipher = Cipher.getInstance(ALGORITHM); + cipher.init(Cipher.ENCRYPT_MODE, secretKeySpec); + byte[] encryptedBytes = cipher.doFinal(data.getBytes(StandardCharsets.UTF_8)); + return Base64.encode(encryptedBytes); + } + + private static String decrypt(String encryptedData, String key) throws Exception { + SecretKeySpec secretKeySpec = new SecretKeySpec(Base64.decode(key), ALGORITHM); + Cipher cipher = Cipher.getInstance(ALGORITHM); + cipher.init(Cipher.DECRYPT_MODE, secretKeySpec); + byte[] decryptedBytes = cipher.doFinal(Base64.decode(encryptedData)); + return new String(decryptedBytes, StandardCharsets.UTF_8); + } + + @Override + public void licencesDiscern(String encryptionStr) { + if (Util.isNullOrEmpty(encryptionStr)) { + throw exception(ENCRYPTION_STR_FORMAT_IS_ERROR); + } + try { + //todo 数据校验 + JSONObject codeJson = JSONObject.parseObject(encryptionStr); + String secretKey = codeJson.getString("secretKey"); + if (Util.isNullOrEmpty(secretKey)) { + throw exception(ENCRYPTION_STR_FORMAT_IS_ERROR); + } + String dataStr = codeJson.getString("data"); + if (Util.isNullOrEmpty(dataStr)) { + throw exception(ENCRYPTION_STR_FORMAT_IS_ERROR); + } + JSONArray dataJson = JSONArray.parseArray(decrypt(dataStr, secretKey)); + if (dataJson.isEmpty()) { + throw exception(ENCRYPTION_STR_FORMAT_IS_ERROR); + } + //todo 更新到redis并使用发布订阅通知其他pods + redisTemplate.opsForValue().set(LICENCES_UPDATE, dataJson.toJSONString()); + redisTemplate.convertAndSend(LICENCES_UPDATE, 1); + } catch (Exception e) { + throw exception(500, e); + } + } + + @Override + public void generateLicence(GenerateLicenceReqVO req, HttpServletResponse response) throws Exception { + LicencesMessage licencesMessage = new LicencesMessage() {{ + String secretKey = generateKey(); + setSecretKey(secretKey); + List data = new ArrayList(); + MD5 md5 = MD5.create(); + data.add(new JSONObject(){{ + put(md5.digestHex("/MES"),encrypt("2025-10-10 00:00:00",secretKey)); + }}.toJSONString()); + data.add(new JSONObject(){{ + put(md5.digestHex("/WMS"),encrypt("2025-10-10 00:00:00",secretKey)); + }}.toJSONString()); + setData(encrypt(JSONObject.toJSONString(data),secretKey)); + }}; + QrConfig config = new QrConfig(300, 300); + config.setErrorCorrection(com.google.zxing.qrcode.decoder.ErrorCorrectionLevel.M); // 设置纠错级别 + // 或者直接输出到流 + QrCodeUtil.generate(JSONObject.toJSONString(licencesMessage), config, ImageData.ImageType.PICTURE_TYPE_DIB.name(), response.getOutputStream()); + } +}