diff --git a/fuintAdmin/src/api/EventMarketing/cardExchange.js b/fuintAdmin/src/api/EventMarketing/cardExchange.js
new file mode 100644
index 000000000..37cbfa48c
--- /dev/null
+++ b/fuintAdmin/src/api/EventMarketing/cardExchange.js
@@ -0,0 +1,44 @@
+import request from '@/utils/request'
+
+// 查询兑换券列表
+export function listExchange(query) {
+ return request({
+ url: '/system/exchange/list',
+ method: 'get',
+ params: query
+ })
+}
+
+// 查询兑换券详细
+export function getExchange(id) {
+ return request({
+ url: '/system/exchange/' + id,
+ method: 'get'
+ })
+}
+
+// 新增兑换券
+export function addExchange(data) {
+ return request({
+ url: '/system/exchange',
+ method: 'post',
+ data: data
+ })
+}
+
+// 修改兑换券
+export function updateExchange(data) {
+ return request({
+ url: '/system/exchange',
+ method: 'put',
+ data: data
+ })
+}
+
+// 删除兑换券
+export function delExchange(id) {
+ return request({
+ url: '/system/exchange/' + id,
+ method: 'delete'
+ })
+}
diff --git a/fuintAdmin/src/api/EventMarketing/cardExchangeRecord.js b/fuintAdmin/src/api/EventMarketing/cardExchangeRecord.js
new file mode 100644
index 000000000..a8c78f376
--- /dev/null
+++ b/fuintAdmin/src/api/EventMarketing/cardExchangeRecord.js
@@ -0,0 +1,44 @@
+import request from '@/utils/request'
+
+// 查询兑换券领取记录列表
+export function listRecord(query) {
+ return request({
+ url: '/system/record/list',
+ method: 'get',
+ params: query
+ })
+}
+
+// 查询兑换券领取记录详细
+export function getRecord(id) {
+ return request({
+ url: '/system/record/' + id,
+ method: 'get'
+ })
+}
+
+// 新增兑换券领取记录
+export function addRecord(data) {
+ return request({
+ url: '/system/record',
+ method: 'post',
+ data: data
+ })
+}
+
+// 修改兑换券领取记录
+export function updateRecord(data) {
+ return request({
+ url: '/system/record',
+ method: 'put',
+ data: data
+ })
+}
+
+// 删除兑换券领取记录
+export function delRecord(id) {
+ return request({
+ url: '/system/record/' + id,
+ method: 'delete'
+ })
+}
diff --git a/fuintAdmin/src/views/EventMarketing/cardExchange/index.vue b/fuintAdmin/src/views/EventMarketing/cardExchange/index.vue
new file mode 100644
index 000000000..a13824680
--- /dev/null
+++ b/fuintAdmin/src/views/EventMarketing/cardExchange/index.vue
@@ -0,0 +1,390 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 搜索
+ 重置
+
+
+
+
+
+ 新增
+
+
+ 修改
+
+
+ 删除
+
+
+ 导出
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ {{ parseTime(scope.row.outTime, '{y}-{m}-{d}') }}
+
+
+
+
+ 修改
+ 删除
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/fuintAdmin/src/views/EventMarketing/cardExchangeRecord/index.vue b/fuintAdmin/src/views/EventMarketing/cardExchangeRecord/index.vue
new file mode 100644
index 000000000..c06007bdb
--- /dev/null
+++ b/fuintAdmin/src/views/EventMarketing/cardExchangeRecord/index.vue
@@ -0,0 +1,484 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 搜索
+ 重置
+
+
+
+
+
+ 新增
+
+
+ 修改
+
+
+ 删除
+
+
+ 导出
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ {{ parseTime(scope.row.outTime, '{y}-{m}-{d}') }}
+
+
+
+
+ {{ parseTime(scope.row.cancelTime, '{y}-{m}-{d}') }}
+
+
+
+
+ {{ parseTime(scope.row.startTime, '{y}-{m}-{d}') }}
+
+
+
+
+ {{ parseTime(scope.row.endTime, '{y}-{m}-{d}') }}
+
+
+
+
+ 修改
+ 删除
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/fuintBackend/fuint-application/src/main/java/com/fuint/business/marketingActivity/cardExchange/controller/CardExchangeController.java b/fuintBackend/fuint-application/src/main/java/com/fuint/business/marketingActivity/cardExchange/controller/CardExchangeController.java
new file mode 100644
index 000000000..48af316cd
--- /dev/null
+++ b/fuintBackend/fuint-application/src/main/java/com/fuint/business/marketingActivity/cardExchange/controller/CardExchangeController.java
@@ -0,0 +1,92 @@
+package com.fuint.business.marketingActivity.cardExchange.controller;
+
+
+
+import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
+import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
+import com.fuint.business.marketingActivity.cardExchange.entity.CardExchange;
+import com.fuint.business.marketingActivity.cardExchange.service.CardExchangeService;
+import com.fuint.framework.web.BaseController;
+import com.fuint.framework.web.ResponseObject;
+import org.apache.ibatis.annotations.Param;
+import org.springframework.web.bind.annotation.*;
+
+import javax.annotation.Resource;
+import java.io.Serializable;
+import java.util.List;
+
+/**
+ * 兑换券(CardExchange)表控制层
+ *
+ * @author makejava
+ * @since 2023-11-06 14:14:17
+ */
+@RestController
+@RequestMapping("business/marketingActivity/cardExchange")
+public class CardExchangeController extends BaseController {
+ /**
+ * 服务对象
+ */
+ @Resource
+ private CardExchangeService cardExchangeService;
+
+ /**
+ * 分页查询所有数据
+ * @param pageNo
+ * @param pageSize
+ * @param cardExchange
+ * @return
+ */
+ @GetMapping
+ public ResponseObject selectAll(@RequestParam(value = "pageNo",defaultValue = "1") Integer pageNo,
+ @RequestParam(value = "pageSize",defaultValue = "10") Integer pageSize,
+ @Param("cardFuelDiesel") CardExchange cardExchange) {
+ Page page = new Page(pageNo, pageSize);
+ return getSuccessResult(this.cardExchangeService.select(page, cardExchange));
+ }
+
+ /**
+ * 通过主键查询单条数据
+ *
+ * @param id 主键
+ * @return 单条数据
+ */
+ @GetMapping("{id}")
+ public ResponseObject selectOne(@PathVariable Serializable id) {
+ return getSuccessResult(this.cardExchangeService.getById(id));
+ }
+
+ /**
+ * 新增数据
+ *
+ * @param cardExchange 实体对象
+ * @return 新增结果
+ */
+ @PostMapping
+ public ResponseObject insert(@RequestBody CardExchange cardExchange) throws Exception {
+ return getSuccessResult(this.cardExchangeService.add(cardExchange));
+ }
+
+ /**
+ * 修改数据
+ *
+ * @param cardExchange 实体对象
+ * @return 修改结果
+ */
+ @PutMapping
+ public ResponseObject update(@RequestBody CardExchange cardExchange) {
+ return getSuccessResult(this.cardExchangeService.updateById(cardExchange));
+ }
+
+ /**
+ * 删除数据
+ *
+ * @param idList 主键结合
+ * @return 删除结果
+ */
+ @DeleteMapping
+ public ResponseObject delete(@RequestParam("idList") List idList) {
+ return getSuccessResult(this.cardExchangeService.removeByIds(idList));
+ }
+}
+
diff --git a/fuintBackend/fuint-application/src/main/java/com/fuint/business/marketingActivity/cardExchange/controller/CardExchangeRecordController.java b/fuintBackend/fuint-application/src/main/java/com/fuint/business/marketingActivity/cardExchange/controller/CardExchangeRecordController.java
new file mode 100644
index 000000000..0d96c01e6
--- /dev/null
+++ b/fuintBackend/fuint-application/src/main/java/com/fuint/business/marketingActivity/cardExchange/controller/CardExchangeRecordController.java
@@ -0,0 +1,105 @@
+package com.fuint.business.marketingActivity.cardExchange.controller;
+
+import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
+import com.fuint.business.marketingActivity.cardExchange.entity.CardExchangeRecord;
+import com.fuint.business.marketingActivity.cardExchange.service.CardExchangeRecordService;
+import com.fuint.framework.web.BaseController;
+import com.fuint.framework.web.ResponseObject;
+import org.apache.ibatis.annotations.Param;
+import org.springframework.web.bind.annotation.*;
+
+import javax.annotation.Resource;
+import java.io.Serializable;
+import java.util.List;
+
+/**
+ * 兑换券领取记录表(CardExchangeRecord)表控制层
+ *
+ * @author makejava
+ * @since 2023-11-06 14:15:07
+ */
+@RestController
+@RequestMapping("business/marketingActivity/cardExchangeRecord")
+public class CardExchangeRecordController extends BaseController {
+ /**
+ * 服务对象
+ */
+ @Resource
+ private CardExchangeRecordService cardExchangeRecordService;
+
+ /**
+ * 分页查询所有数据
+ * @param pageNo
+ * @param pageSize
+ * @param cardExchangeRecord
+ * @return
+ */
+ @GetMapping
+ public ResponseObject selectAll(@RequestParam(value = "pageNo",defaultValue = "1") Integer pageNo,
+ @RequestParam(value = "pageSize",defaultValue = "10") Integer pageSize,
+ @Param("cardFuelDiesel") CardExchangeRecord cardExchangeRecord) {
+ Page page = new Page(pageNo, pageSize);
+ return getSuccessResult(this.cardExchangeRecordService.select(page,cardExchangeRecord));
+ }
+
+
+ /**
+ * 分页查询已使用兑换券
+ * @param pageNo
+ * @param pageSize
+ * @param cardExchangeRecord
+ * @return
+ */
+ @GetMapping("list")
+ public ResponseObject selectIsUsed(@RequestParam(value = "pageNo",defaultValue = "1") Integer pageNo,
+ @RequestParam(value = "pageSize",defaultValue = "10") Integer pageSize,
+ @Param("cardFuelDiesel") CardExchangeRecord cardExchangeRecord) {
+ Page page = new Page(pageNo, pageSize);
+ return getSuccessResult(this.cardExchangeRecordService.selectIsUsed(page,cardExchangeRecord));
+ }
+
+ /**
+ * 通过主键查询单条数据
+ *
+ * @param id 主键
+ * @return 单条数据
+ */
+ @GetMapping("{id}")
+ public ResponseObject selectOne(@PathVariable Serializable id) {
+ return getSuccessResult(this.cardExchangeRecordService.getById(id));
+ }
+
+ /**
+ * 新增数据
+ *
+ * @param cardExchangeRecord 实体对象
+ * @return 新增结果
+ */
+ @PostMapping
+ public ResponseObject insert(@RequestBody CardExchangeRecord cardExchangeRecord) {
+ return getSuccessResult(this.cardExchangeRecordService.save(cardExchangeRecord));
+ }
+
+ /**
+ * 修改数据
+ *
+ * @param cardExchangeRecord 实体对象
+ * @return 修改结果
+ */
+ @PutMapping
+ public ResponseObject update(@RequestBody CardExchangeRecord cardExchangeRecord) {
+ return getSuccessResult(this.cardExchangeRecordService.updateById(cardExchangeRecord));
+ }
+
+ /**
+ * 删除数据
+ *
+ * @param idList 主键结合
+ * @return 删除结果
+ */
+ @DeleteMapping
+ public ResponseObject delete(@RequestParam("idList") List idList) {
+ return getSuccessResult(this.cardExchangeRecordService.removeByIds(idList));
+ }
+}
+
diff --git a/fuintBackend/fuint-application/src/main/java/com/fuint/business/marketingActivity/cardExchange/entity/CardExchange.java b/fuintBackend/fuint-application/src/main/java/com/fuint/business/marketingActivity/cardExchange/entity/CardExchange.java
new file mode 100644
index 000000000..1971723da
--- /dev/null
+++ b/fuintBackend/fuint-application/src/main/java/com/fuint/business/marketingActivity/cardExchange/entity/CardExchange.java
@@ -0,0 +1,206 @@
+package com.fuint.business.marketingActivity.cardExchange.entity;
+
+import java.util.Date;
+
+import com.baomidou.mybatisplus.annotation.IdType;
+import com.baomidou.mybatisplus.annotation.TableId;
+import com.baomidou.mybatisplus.extension.activerecord.Model;
+import com.fasterxml.jackson.annotation.JsonFormat;
+
+import java.io.Serializable;
+
+/**
+ * 兑换券(CardExchange)表实体类
+ *
+ * @author makejava
+ * @since 2023-11-06 14:14:17
+ */
+@SuppressWarnings("serial")
+public class CardExchange extends Model {
+ //主键id
+ @TableId(type = IdType.AUTO)
+ private Integer id;
+ //所属连锁店id
+ private Integer chainStorId;
+ //所属店铺id
+ private Integer storeId;
+ //是否在线 0:在线 1: 下线
+ private String isonline;
+ //兑换券状态 0:启用 1: 禁用
+ private String status;
+ //兑换券名称
+ private String name;
+ //兑换券类型 0:兑换券 1:洗车券 2:洗车卡
+ private String type;
+ //兑换礼品名
+ private String giftName;
+ //卡券有效期
+ private Integer validity;
+ //使用说明
+ private String useInstructions;
+ //二维码链接
+ private String qrCodeLink;
+ //参与次数
+ private Integer count;
+ //过期时间
+ @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
+ private Date outTime;
+ //创建者
+ private String createBy;
+ //创建时间
+ @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
+ private Date createTime;
+ //更新者
+ private String updateBy;
+ //更新时间
+ @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
+ private Date updateTime;
+
+
+ public Integer getId() {
+ return id;
+ }
+
+ public void setId(Integer id) {
+ this.id = id;
+ }
+
+ public Integer getChainStorId() {
+ return chainStorId;
+ }
+
+ public void setChainStorId(Integer chainStorId) {
+ this.chainStorId = chainStorId;
+ }
+
+ public Integer getStoreId() {
+ return storeId;
+ }
+
+ public void setStoreId(Integer storeId) {
+ this.storeId = storeId;
+ }
+
+ public String getIsonline() {
+ return isonline;
+ }
+
+ public void setIsonline(String isonline) {
+ this.isonline = isonline;
+ }
+
+ public String getStatus() {
+ return status;
+ }
+
+ public void setStatus(String status) {
+ this.status = status;
+ }
+
+ public String getName() {
+ return name;
+ }
+
+ public void setName(String name) {
+ this.name = name;
+ }
+
+ public String getType() {
+ return type;
+ }
+
+ public void setType(String type) {
+ this.type = type;
+ }
+
+ public String getGiftName() {
+ return giftName;
+ }
+
+ public void setGiftName(String giftName) {
+ this.giftName = giftName;
+ }
+
+ public Integer getValidity() {
+ return validity;
+ }
+
+ public void setValidity(Integer validity) {
+ this.validity = validity;
+ }
+
+ public String getUseInstructions() {
+ return useInstructions;
+ }
+
+ public void setUseInstructions(String useInstructions) {
+ this.useInstructions = useInstructions;
+ }
+
+ public String getQrCodeLink() {
+ return qrCodeLink;
+ }
+
+ public void setQrCodeLink(String qrCodeLink) {
+ this.qrCodeLink = qrCodeLink;
+ }
+
+ public Integer getCount() {
+ return count;
+ }
+
+ public void setCount(Integer count) {
+ this.count = count;
+ }
+
+ public Date getOutTime() {
+ return outTime;
+ }
+
+ public void setOutTime(Date outTime) {
+ this.outTime = outTime;
+ }
+
+ public String getCreateBy() {
+ return createBy;
+ }
+
+ public void setCreateBy(String createBy) {
+ this.createBy = createBy;
+ }
+
+ public Date getCreateTime() {
+ return createTime;
+ }
+
+ public void setCreateTime(Date createTime) {
+ this.createTime = createTime;
+ }
+
+ public String getUpdateBy() {
+ return updateBy;
+ }
+
+ public void setUpdateBy(String updateBy) {
+ this.updateBy = updateBy;
+ }
+
+ public Date getUpdateTime() {
+ return updateTime;
+ }
+
+ public void setUpdateTime(Date updateTime) {
+ this.updateTime = updateTime;
+ }
+
+ /**
+ * 获取主键值
+ *
+ * @return 主键值
+ */
+ @Override
+ protected Serializable pkVal() {
+ return this.id;
+ }
+ }
+
diff --git a/fuintBackend/fuint-application/src/main/java/com/fuint/business/marketingActivity/cardExchange/entity/CardExchangeRecord.java b/fuintBackend/fuint-application/src/main/java/com/fuint/business/marketingActivity/cardExchange/entity/CardExchangeRecord.java
new file mode 100644
index 000000000..cd753ab40
--- /dev/null
+++ b/fuintBackend/fuint-application/src/main/java/com/fuint/business/marketingActivity/cardExchange/entity/CardExchangeRecord.java
@@ -0,0 +1,235 @@
+package com.fuint.business.marketingActivity.cardExchange.entity;
+
+import java.util.Date;
+
+import com.baomidou.mybatisplus.annotation.IdType;
+import com.baomidou.mybatisplus.annotation.TableId;
+import com.baomidou.mybatisplus.extension.activerecord.Model;
+import com.fasterxml.jackson.annotation.JsonFormat;
+
+import java.io.Serializable;
+
+/**
+ * 兑换券领取记录表(CardExchangeRecord)表实体类
+ *
+ * @author makejava
+ * @since 2023-11-06 14:15:07
+ */
+@SuppressWarnings("serial")
+public class CardExchangeRecord extends Model {
+ //主键id
+ @TableId(type = IdType.AUTO)
+ private Integer id;
+ //兑换券id
+ private Integer cardExchangeId;
+ //员工id
+ private Integer mtStaffId;
+ //员工姓名
+ private String realName;
+ //员工手机号码
+ private String staffMobile;
+ //会员id
+ private Integer mtUserId;
+ //会员手机号码
+ private String mobile;
+ //会员头像
+ private String photo;
+ //券名称
+ private String exchangeName;
+ //券码
+ private String ticketCode;
+ //券来源
+ private String exchangeFrom;
+ //使用状态 :0 :未使用 1:已使用
+ private String status;
+ //创建者
+ private String createBy;
+ //创建时间
+ private Date createTime;
+ //更新者
+ private String updateBy;
+ //更新时间
+ private Date updateTime;
+ //到期时间
+ private Date outTime;
+ //核销时间
+ private Date cancelTime;
+
+ //创建时间
+ private Date startTime;
+
+ //创建时间
+ private Date endTime;
+
+
+ public Integer getId() {
+ return id;
+ }
+
+ public void setId(Integer id) {
+ this.id = id;
+ }
+
+ public Integer getCardExchangeId() {
+ return cardExchangeId;
+ }
+
+ public void setCardExchangeId(Integer cardExchangeId) {
+ this.cardExchangeId = cardExchangeId;
+ }
+
+ public Integer getMtStaffId() {
+ return mtStaffId;
+ }
+
+ public void setMtStaffId(Integer mtStaffId) {
+ this.mtStaffId = mtStaffId;
+ }
+
+ public String getRealName() {
+ return realName;
+ }
+
+ public void setRealName(String realName) {
+ this.realName = realName;
+ }
+
+ public String getStaffMobile() {
+ return staffMobile;
+ }
+
+ public void setStaffMobile(String staffMobile) {
+ this.staffMobile = staffMobile;
+ }
+
+ public Integer getMtUserId() {
+ return mtUserId;
+ }
+
+ public void setMtUserId(Integer mtUserId) {
+ this.mtUserId = mtUserId;
+ }
+
+ public String getMobile() {
+ return mobile;
+ }
+
+ public void setMobile(String mobile) {
+ this.mobile = mobile;
+ }
+
+ public String getPhoto() {
+ return photo;
+ }
+
+ public void setPhoto(String photo) {
+ this.photo = photo;
+ }
+
+ public String getExchangeName() {
+ return exchangeName;
+ }
+
+ public void setExchangeName(String exchangeName) {
+ this.exchangeName = exchangeName;
+ }
+
+ public String getTicketCode() {
+ return ticketCode;
+ }
+
+ public void setTicketCode(String ticketCode) {
+ this.ticketCode = ticketCode;
+ }
+
+ public String getExchangeFrom() {
+ return exchangeFrom;
+ }
+
+ public void setExchangeFrom(String exchangeFrom) {
+ this.exchangeFrom = exchangeFrom;
+ }
+
+ public String getStatus() {
+ return status;
+ }
+
+ public void setStatus(String status) {
+ this.status = status;
+ }
+
+ public String getCreateBy() {
+ return createBy;
+ }
+
+ public void setCreateBy(String createBy) {
+ this.createBy = createBy;
+ }
+
+ public Date getCreateTime() {
+ return createTime;
+ }
+
+ public void setCreateTime(Date createTime) {
+ this.createTime = createTime;
+ }
+
+ public String getUpdateBy() {
+ return updateBy;
+ }
+
+ public void setUpdateBy(String updateBy) {
+ this.updateBy = updateBy;
+ }
+
+ public Date getUpdateTime() {
+ return updateTime;
+ }
+
+ public void setUpdateTime(Date updateTime) {
+ this.updateTime = updateTime;
+ }
+
+ public Date getOutTime() {
+ return outTime;
+ }
+
+ public void setOutTime(Date outTime) {
+ this.outTime = outTime;
+ }
+
+ public Date getCancelTime() {
+ return cancelTime;
+ }
+
+ public void setCancelTime(Date cancelTime) {
+ this.cancelTime = cancelTime;
+ }
+
+ public Date getStartTime() {
+ return startTime;
+ }
+
+ public void setStartTime(Date startTime) {
+ this.startTime = startTime;
+ }
+
+ public Date getEndTime() {
+ return endTime;
+ }
+
+ public void setEndTime(Date endTime) {
+ this.endTime = endTime;
+ }
+
+ /**
+ * 获取主键值
+ *
+ * @return 主键值
+ */
+ @Override
+ protected Serializable pkVal() {
+ return this.id;
+ }
+ }
+
diff --git a/fuintBackend/fuint-application/src/main/java/com/fuint/business/marketingActivity/cardExchange/mapper/CardExchangeMapper.java b/fuintBackend/fuint-application/src/main/java/com/fuint/business/marketingActivity/cardExchange/mapper/CardExchangeMapper.java
new file mode 100644
index 000000000..7ab506b50
--- /dev/null
+++ b/fuintBackend/fuint-application/src/main/java/com/fuint/business/marketingActivity/cardExchange/mapper/CardExchangeMapper.java
@@ -0,0 +1,15 @@
+package com.fuint.business.marketingActivity.cardExchange.mapper;
+
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import com.fuint.business.marketingActivity.cardExchange.entity.CardExchange;
+
+/**
+ * 兑换券(CardExchange)表数据库访问层
+ *
+ * @author makejava
+ * @since 2023-11-06 14:14:17
+ */
+public interface CardExchangeMapper extends BaseMapper {
+
+}
+
diff --git a/fuintBackend/fuint-application/src/main/java/com/fuint/business/marketingActivity/cardExchange/mapper/CardExchangeRecordMapper.java b/fuintBackend/fuint-application/src/main/java/com/fuint/business/marketingActivity/cardExchange/mapper/CardExchangeRecordMapper.java
new file mode 100644
index 000000000..566947873
--- /dev/null
+++ b/fuintBackend/fuint-application/src/main/java/com/fuint/business/marketingActivity/cardExchange/mapper/CardExchangeRecordMapper.java
@@ -0,0 +1,15 @@
+package com.fuint.business.marketingActivity.cardExchange.mapper;
+
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import com.fuint.business.marketingActivity.cardExchange.entity.CardExchangeRecord;
+
+/**
+ * 兑换券领取记录表(CardExchangeRecord)表数据库访问层
+ *
+ * @author makejava
+ * @since 2023-11-06 14:15:07
+ */
+public interface CardExchangeRecordMapper extends BaseMapper {
+
+}
+
diff --git a/fuintBackend/fuint-application/src/main/java/com/fuint/business/marketingActivity/cardExchange/service/CardExchangeRecordService.java b/fuintBackend/fuint-application/src/main/java/com/fuint/business/marketingActivity/cardExchange/service/CardExchangeRecordService.java
new file mode 100644
index 000000000..8a84e7070
--- /dev/null
+++ b/fuintBackend/fuint-application/src/main/java/com/fuint/business/marketingActivity/cardExchange/service/CardExchangeRecordService.java
@@ -0,0 +1,32 @@
+package com.fuint.business.marketingActivity.cardExchange.service;
+
+import com.baomidou.mybatisplus.core.metadata.IPage;
+import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
+import com.baomidou.mybatisplus.extension.service.IService;
+import com.fuint.business.marketingActivity.cardExchange.entity.CardExchangeRecord;
+
+/**
+ * 兑换券领取记录表(CardExchangeRecord)表服务接口
+ *
+ * @author makejava
+ * @since 2023-11-06 14:15:07
+ */
+public interface CardExchangeRecordService extends IService {
+
+ /**
+ * 分页查询
+ * @param page
+ * @param cardExchangeRecord
+ * @return
+ */
+ IPage select(Page page, CardExchangeRecord cardExchangeRecord);
+
+ /**
+ * 分页查询已使用数据
+ * @param page
+ * @param cardExchangeRecord
+ * @return
+ */
+ IPage selectIsUsed(Page page, CardExchangeRecord cardExchangeRecord);
+}
+
diff --git a/fuintBackend/fuint-application/src/main/java/com/fuint/business/marketingActivity/cardExchange/service/CardExchangeService.java b/fuintBackend/fuint-application/src/main/java/com/fuint/business/marketingActivity/cardExchange/service/CardExchangeService.java
new file mode 100644
index 000000000..220f3ee17
--- /dev/null
+++ b/fuintBackend/fuint-application/src/main/java/com/fuint/business/marketingActivity/cardExchange/service/CardExchangeService.java
@@ -0,0 +1,32 @@
+package com.fuint.business.marketingActivity.cardExchange.service;
+
+import com.baomidou.mybatisplus.core.metadata.IPage;
+import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
+import com.baomidou.mybatisplus.extension.service.IService;
+import com.fuint.business.marketingActivity.cardExchange.entity.CardExchange;
+import com.fuint.framework.web.ResponseObject;
+
+/**
+ * 兑换券(CardExchange)表服务接口
+ *
+ * @author makejava
+ * @since 2023-11-06 14:14:17
+ */
+public interface CardExchangeService extends IService {
+
+ /**
+ * 新增数据
+ * @param cardExchange
+ * @return
+ */
+ Boolean add(CardExchange cardExchange) throws Exception;
+
+ /**
+ * 根据条件分页查询
+ * @param page
+ * @param cardExchange
+ * @return
+ */
+ IPage select(Page page, CardExchange cardExchange);
+}
+
diff --git a/fuintBackend/fuint-application/src/main/java/com/fuint/business/marketingActivity/cardExchange/service/impl/CardExchangeRecordServiceImpl.java b/fuintBackend/fuint-application/src/main/java/com/fuint/business/marketingActivity/cardExchange/service/impl/CardExchangeRecordServiceImpl.java
new file mode 100644
index 000000000..ad4a7f6fb
--- /dev/null
+++ b/fuintBackend/fuint-application/src/main/java/com/fuint/business/marketingActivity/cardExchange/service/impl/CardExchangeRecordServiceImpl.java
@@ -0,0 +1,77 @@
+package com.fuint.business.marketingActivity.cardExchange.service.impl;
+
+import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
+import com.baomidou.mybatisplus.core.metadata.IPage;
+import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
+import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
+import com.fuint.business.marketingActivity.cardExchange.mapper.CardExchangeRecordMapper;
+import com.fuint.business.marketingActivity.cardExchange.entity.CardExchangeRecord;
+import com.fuint.business.marketingActivity.cardExchange.service.CardExchangeRecordService;
+import org.apache.commons.lang3.ObjectUtils;
+import org.springframework.stereotype.Service;
+
+/**
+ * 兑换券领取记录表(CardExchangeRecord)表服务实现类
+ *
+ * @author makejava
+ * @since 2023-11-06 14:15:07
+ */
+@Service("cardExchangeRecordService")
+public class CardExchangeRecordServiceImpl extends ServiceImpl implements CardExchangeRecordService {
+
+ /**
+ * 分页查询
+ * @param page
+ * @param cardExchangeRecord
+ * @return
+ */
+ @Override
+ public IPage select(Page page, CardExchangeRecord cardExchangeRecord) {
+ //构建查询条件
+ LambdaQueryWrapper queryWrapper = new LambdaQueryWrapper<>();
+ if(ObjectUtils.isNotEmpty(cardExchangeRecord.getExchangeName())){
+ queryWrapper.like(CardExchangeRecord::getExchangeName,cardExchangeRecord.getExchangeName());
+ }
+ if (ObjectUtils.isNotEmpty(cardExchangeRecord.getMobile())){
+ queryWrapper.eq(CardExchangeRecord::getMobile,cardExchangeRecord.getMobile());
+ }
+ if(ObjectUtils.isNotEmpty(cardExchangeRecord.getStatus())) {
+ queryWrapper.eq(CardExchangeRecord::getStatus,cardExchangeRecord.getStatus());
+ }
+ if(ObjectUtils.isNotEmpty(cardExchangeRecord.getTicketCode())) {
+ queryWrapper.eq(CardExchangeRecord::getTicketCode,cardExchangeRecord.getTicketCode());
+ }
+ queryWrapper.orderByDesc(CardExchangeRecord::getCreateTime);
+ return page(page, queryWrapper);
+ }
+
+ /**
+ * 分页查询已使用数据
+ * @param page
+ * @param cardExchangeRecord
+ * @return
+ */
+ @Override
+ public IPage selectIsUsed(Page page, CardExchangeRecord cardExchangeRecord) {
+ //构建查询条件
+ LambdaQueryWrapper queryWrapper = new LambdaQueryWrapper<>();
+ if(ObjectUtils.isNotEmpty(cardExchangeRecord.getExchangeName())){
+ queryWrapper.like(CardExchangeRecord::getExchangeName,cardExchangeRecord.getExchangeName());
+ }
+ //会员手机号
+ if (ObjectUtils.isNotEmpty(cardExchangeRecord.getMobile())){
+ queryWrapper.eq(CardExchangeRecord::getMobile,cardExchangeRecord.getMobile());
+ }
+ //员工手机号
+ if (ObjectUtils.isNotEmpty(cardExchangeRecord.getStaffMobile())){
+ queryWrapper.eq(CardExchangeRecord::getStaffMobile,cardExchangeRecord.getStaffMobile());
+ }
+ queryWrapper.eq(CardExchangeRecord::getStatus,"1");
+ if (ObjectUtils.isNotEmpty(cardExchangeRecord.getStartTime()) && ObjectUtils.isNotEmpty(cardExchangeRecord.getEndTime()) ) {
+ queryWrapper.between(CardExchangeRecord::getCancelTime,cardExchangeRecord.getStartTime(),cardExchangeRecord.getEndTime());
+ }
+ queryWrapper.orderByDesc(CardExchangeRecord::getCreateTime);
+ return page(page, queryWrapper);
+ }
+}
+
diff --git a/fuintBackend/fuint-application/src/main/java/com/fuint/business/marketingActivity/cardExchange/service/impl/CardExchangeServiceImpl.java b/fuintBackend/fuint-application/src/main/java/com/fuint/business/marketingActivity/cardExchange/service/impl/CardExchangeServiceImpl.java
new file mode 100644
index 000000000..20b9b34c8
--- /dev/null
+++ b/fuintBackend/fuint-application/src/main/java/com/fuint/business/marketingActivity/cardExchange/service/impl/CardExchangeServiceImpl.java
@@ -0,0 +1,81 @@
+package com.fuint.business.marketingActivity.cardExchange.service.impl;
+
+import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
+import com.baomidou.mybatisplus.core.metadata.IPage;
+import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
+import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
+import com.fuint.business.marketingActivity.cardExchange.mapper.CardExchangeMapper;
+import com.fuint.business.marketingActivity.cardExchange.entity.CardExchange;
+import com.fuint.business.marketingActivity.cardExchange.service.CardExchangeService;
+import com.fuint.business.store.service.StoreService;
+import com.fuint.common.util.CryptoUtils;
+import com.fuint.common.util.TokenUtil;
+import org.apache.commons.lang3.ObjectUtils;
+import org.springframework.stereotype.Service;
+
+import javax.annotation.Resource;
+import java.util.Date;
+
+/**
+ * 兑换券(CardExchange)表服务实现类
+ *
+ * @author makejava
+ * @since 2023-11-06 14:14:17
+ */
+@Service("cardExchangeService")
+public class CardExchangeServiceImpl extends ServiceImpl implements CardExchangeService {
+
+ @Resource
+ private StoreService storeService;
+ /**
+ * 新增数据
+ * @param cardExchange
+ * @return
+ */
+ @Override
+ public Boolean add(CardExchange cardExchange) throws Exception {
+ //获取当前店铺的id和连锁店id
+ if (ObjectUtils.isNotEmpty(TokenUtil.getNowAccountInfo().getStoreId())) {
+ cardExchange.setStoreId(TokenUtil.getNowAccountInfo().getStoreId());
+ cardExchange.setChainStorId(storeService.getById(TokenUtil.getNowAccountInfo().getStoreId()).getChainStoreId());
+ }
+ //设置过期时间
+ Integer validity = cardExchange.getValidity();
+ long time = new Date().getTime();
+ long i = (long)validity * 1;
+ cardExchange.setOutTime(new Date(time + i));
+ //二维码链接加密
+ String qr_code_link = "12132";
+ cardExchange.setQrCodeLink(qr_code_link);
+ String secretKey = "sQPoC/1do9BZMkg8I5c09A==";
+ CryptoUtils.encryptSymmetrically(secretKey, null,cardExchange.getQrCodeLink(), CryptoUtils.Algorithm.Encryption.AES_ECB_PKCS5);
+ return save(cardExchange);
+ }
+
+ /**
+ * 根据条件分页查询
+ * @param page
+ * @param cardExchange
+ * @return
+ */
+ @Override
+ public IPage select(Page page, CardExchange cardExchange) {
+ //构建查询条件
+ LambdaQueryWrapper queryWrapper = new LambdaQueryWrapper<>();
+ if(ObjectUtils.isNotEmpty(cardExchange.getName())){
+ queryWrapper.like(CardExchange::getName,cardExchange.getName());
+ }
+ if (ObjectUtils.isNotEmpty(cardExchange.getType())){
+ queryWrapper.eq(CardExchange::getType,cardExchange.getType());
+ }
+ if(ObjectUtils.isNotEmpty(cardExchange.getStatus())) {
+ queryWrapper.eq(CardExchange::getStatus,cardExchange.getStatus());
+ }
+ if(ObjectUtils.isNotEmpty(cardExchange.getIsonline())) {
+ queryWrapper.eq(CardExchange::getIsonline,cardExchange.getIsonline());
+ }
+ queryWrapper.orderByDesc(CardExchange::getCreateTime);
+ return page(page, queryWrapper);
+ }
+}
+
diff --git a/fuintBackend/fuint-application/src/main/java/com/fuint/business/marketingActivity/cardFule/controller/CardFuelDieselController.java b/fuintBackend/fuint-application/src/main/java/com/fuint/business/marketingActivity/cardFule/controller/CardFuelDieselController.java
index 5c22c694a..e688dd868 100644
--- a/fuintBackend/fuint-application/src/main/java/com/fuint/business/marketingActivity/cardFule/controller/CardFuelDieselController.java
+++ b/fuintBackend/fuint-application/src/main/java/com/fuint/business/marketingActivity/cardFule/controller/CardFuelDieselController.java
@@ -54,8 +54,8 @@ public class CardFuelDieselController extends BaseController {
if(ObjectUtils.isNotEmpty(cardFuelDiesel.getOilType())){
queryWrapper.eq(CardFuelDiesel::getOilType,cardFuelDiesel.getOilType());
}
- if (ObjectUtils.isNotEmpty(cardFuelDiesel.getStatus())){
- queryWrapper.eq(CardFuelDiesel::getStatus,cardFuelDiesel.getStatus().equals("true") ? "1" : "2");
+ if (ObjectUtils.isNotEmpty(cardFuelDiesel.getActiveStatus())){
+ queryWrapper.eq(CardFuelDiesel::getActiveStatus,cardFuelDiesel.getActiveStatus());
}
if(ObjectUtils.isNotEmpty(cardFuelDiesel.getType())) {
queryWrapper.eq(CardFuelDiesel::getType,cardFuelDiesel.getType());
diff --git a/fuintBackend/fuint-application/src/main/java/com/fuint/business/marketingActivity/cardGift/controller/CardGiftController.java b/fuintBackend/fuint-application/src/main/java/com/fuint/business/marketingActivity/cardGift/controller/CardGiftController.java
index 3ad021081..ad3a1afc9 100644
--- a/fuintBackend/fuint-application/src/main/java/com/fuint/business/marketingActivity/cardGift/controller/CardGiftController.java
+++ b/fuintBackend/fuint-application/src/main/java/com/fuint/business/marketingActivity/cardGift/controller/CardGiftController.java
@@ -58,7 +58,7 @@ public class CardGiftController extends BaseController {
if(ObjectUtils.isNotEmpty(cardGift.getActivateStatus())) {
queryWrapper.eq(CardGift::getActivateStatus,cardGift.getActivateStatus());
}
- if(ObjectUtils.isNotEmpty(cardGift.getActivateStatus())) {
+ if(ObjectUtils.isNotEmpty(cardGift.getStatus())) {
queryWrapper.eq(CardGift::getStatus,cardGift.getStatus());
}
queryWrapper.orderByDesc(CardGift::getCreateTime);
diff --git a/fuintBackend/fuint-application/src/main/java/com/fuint/business/marketingActivity/cardGift/entity/CardGift.java b/fuintBackend/fuint-application/src/main/java/com/fuint/business/marketingActivity/cardGift/entity/CardGift.java
index dd536f80e..46e25bd63 100644
--- a/fuintBackend/fuint-application/src/main/java/com/fuint/business/marketingActivity/cardGift/entity/CardGift.java
+++ b/fuintBackend/fuint-application/src/main/java/com/fuint/business/marketingActivity/cardGift/entity/CardGift.java
@@ -31,6 +31,8 @@ public class CardGift extends Model {
private Integer storeId;
//礼品卡状态 1:在用 2:挂失 3:停用
private String status;
+ //兑换功能状态 0:启用 1:禁用
+ private String exchangeStatus;
//激活状态
private String activateStatus;
//生成数量
@@ -115,6 +117,14 @@ public class CardGift extends Model {
this.activateStatus = activateStatus;
}
+ public String getExchangeStatus() {
+ return exchangeStatus;
+ }
+
+ public void setExchangeStatus(String exchangeStatus) {
+ this.exchangeStatus = exchangeStatus;
+ }
+
public Integer getQuantity() {
return quantity;
}
diff --git a/fuintBackend/fuint-application/src/main/java/com/fuint/business/marketingActivity/cardGift/service/impl/CardGiftServiceImpl.java b/fuintBackend/fuint-application/src/main/java/com/fuint/business/marketingActivity/cardGift/service/impl/CardGiftServiceImpl.java
index 2d67eeb26..902c47302 100644
--- a/fuintBackend/fuint-application/src/main/java/com/fuint/business/marketingActivity/cardGift/service/impl/CardGiftServiceImpl.java
+++ b/fuintBackend/fuint-application/src/main/java/com/fuint/business/marketingActivity/cardGift/service/impl/CardGiftServiceImpl.java
@@ -10,6 +10,7 @@ import com.fuint.business.oilDepotConfiguration.service.OilDepotConfigService;
import com.fuint.business.store.service.StoreService;
import com.fuint.common.util.TokenUtil;
import org.apache.commons.lang3.ObjectUtils;
+import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Service;
import javax.annotation.Resource;
@@ -85,6 +86,10 @@ public class CardGiftServiceImpl extends ServiceImpl i
LambdaQueryWrapper queryWrapper = new LambdaQueryWrapper<>();
queryWrapper.eq(OilDepotConfig::getStoreId, storeId);
OilDepotConfig oilDepotConfig = oilDepotConfigService.getOne(queryWrapper);
+ //礼品卡兑换功能状态
+ if (ObjectUtils.isNotEmpty(oilDepotConfig) && StringUtils.isNotEmpty(oilDepotConfig.getExchangeStatus())){
+ map.put("exchangeStatus",oilDepotConfig.getExchangeStatus().equals("0") ? 0L : 1L);
+ }
if (ObjectUtils.isNotEmpty(oilDepotConfig)) {
map.put("total_amount", (long) oilDepotConfig.getTotalAmount());
//礼品卡剩余额度
diff --git a/fuintBackend/fuint-application/src/main/java/com/fuint/business/oilDepotConfiguration/entity/OilDepotConfig.java b/fuintBackend/fuint-application/src/main/java/com/fuint/business/oilDepotConfiguration/entity/OilDepotConfig.java
index abc93b92d..8a19306d7 100644
--- a/fuintBackend/fuint-application/src/main/java/com/fuint/business/oilDepotConfiguration/entity/OilDepotConfig.java
+++ b/fuintBackend/fuint-application/src/main/java/com/fuint/business/oilDepotConfiguration/entity/OilDepotConfig.java
@@ -23,6 +23,8 @@ public class OilDepotConfig extends Model {
private Integer storeId;
//礼品卡数量总额度
private Integer totalAmount;
+ //礼品卡兑换状态
+ private String exchangeStatus;
//创建者
private String createBy;
//创建时间
@@ -65,6 +67,14 @@ public class OilDepotConfig extends Model {
this.totalAmount = totalAmount;
}
+ public String getExchangeStatus() {
+ return exchangeStatus;
+ }
+
+ public void setExchangeStatus(String exchangeStatus) {
+ this.exchangeStatus = exchangeStatus;
+ }
+
public String getCreateBy() {
return createBy;
}
diff --git a/fuintBackend/fuint-application/src/main/java/com/fuint/common/util/CryptoUtils.java b/fuintBackend/fuint-application/src/main/java/com/fuint/common/util/CryptoUtils.java
new file mode 100644
index 000000000..7e64077c5
--- /dev/null
+++ b/fuintBackend/fuint-application/src/main/java/com/fuint/common/util/CryptoUtils.java
@@ -0,0 +1,297 @@
+package com.fuint.common.util;
+
+import lombok.AllArgsConstructor;
+import lombok.Data;
+import lombok.Getter;
+import lombok.NoArgsConstructor;
+import org.apache.commons.lang3.StringUtils;
+
+import javax.crypto.Cipher;
+import javax.crypto.KeyGenerator;
+import javax.crypto.NoSuchPaddingException;
+import javax.crypto.SecretKey;
+import javax.crypto.spec.IvParameterSpec;
+import javax.crypto.spec.SecretKeySpec;
+import java.nio.charset.Charset;
+import java.nio.charset.StandardCharsets;
+import java.security.Key;
+import java.security.KeyFactory;
+import java.security.NoSuchAlgorithmException;
+import java.security.PrivateKey;
+import java.security.PublicKey;
+import java.security.Signature;
+import java.security.spec.InvalidKeySpecException;
+import java.security.spec.KeySpec;
+import java.security.spec.PKCS8EncodedKeySpec;
+import java.security.spec.X509EncodedKeySpec;
+import java.util.Base64;
+import java.util.Base64.Decoder;
+import java.util.Base64.Encoder;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
+
+/**
+ * 支持AES、DES、RSA加密、数字签名以及生成对称密钥和非对称密钥对
+ */
+public class CryptoUtils {
+
+ private static final Charset DEFAULT_CHARSET = StandardCharsets.UTF_8;
+ private static final Encoder BASE64_ENCODER = Base64.getEncoder();
+ private static final Decoder BASE64_DECODER = Base64.getDecoder();
+
+ private static final Map KEY_FACTORY_CACHE = new ConcurrentHashMap<>();
+ private static final Map CIPHER_CACHE = new HashMap<>();
+
+ /**
+ * 生成对称密钥,目前支持的算法有AES、DES
+ * @param algorithm
+ * @return
+ * @throws NoSuchAlgorithmException
+ */
+ public static String generateSymmetricKey(Algorithm algorithm) throws NoSuchAlgorithmException {
+ KeyGenerator generator = KeyGenerator.getInstance(algorithm.getName());
+ generator.init(algorithm.getKeySize());
+ SecretKey secretKey = generator.generateKey();
+ return BASE64_ENCODER.encodeToString(secretKey.getEncoded());
+ }
+
+ /**
+ * 对称加密
+ * @param secretKey 密钥
+ * @param iv 加密向量,只有CBC模式才支持,如果是CBC则必传
+ * @param plainText 明文
+ * @param algorithm 对称加密算法,如AES、DES
+ * @return
+ * @throws Exception
+ */
+ public static String encryptSymmetrically(String secretKey, String iv, String plainText, Algorithm algorithm) throws Exception {
+ SecretKey key = decodeSymmetricKey(secretKey, algorithm);
+ IvParameterSpec ivParameterSpec = StringUtils.isBlank(iv) ? null : decodeIv(iv);
+ byte[] plainTextInBytes = plainText.getBytes(DEFAULT_CHARSET);
+ byte[] ciphertextInBytes = transform(algorithm, Cipher.ENCRYPT_MODE, key, ivParameterSpec, plainTextInBytes);
+
+ return BASE64_ENCODER.encodeToString(ciphertextInBytes);
+ }
+
+ /**
+ * 对称解密
+ * @param secretKey 密钥
+ * @param iv 加密向量,只有CBC模式才支持,如果是CBC则必传
+ * @param ciphertext 密文
+ * @param algorithm 对称加密算法,如AES、DES
+ * @return
+ * @throws Exception
+ */
+ public static String decryptSymmetrically(String secretKey, String iv, String ciphertext, Algorithm algorithm) throws Exception {
+ SecretKey key = decodeSymmetricKey(secretKey, algorithm);
+ IvParameterSpec ivParameterSpec = StringUtils.isBlank(iv) ? null : decodeIv(iv);
+ byte[] ciphertextInBytes = BASE64_DECODER.decode(ciphertext);
+ byte[] plainTextInBytes = transform(algorithm, Cipher.DECRYPT_MODE, key, ivParameterSpec, ciphertextInBytes);
+ return new String(plainTextInBytes, DEFAULT_CHARSET);
+ }
+
+ /**
+ * 非对称加密
+ * @param publicKeyText 公钥
+ * @param plainText 明文
+ * @param algorithm 非对称加密算法
+ * @return
+ * @throws Exception
+ */
+ public static String encryptAsymmetrically(String publicKeyText, String plainText, Algorithm algorithm) throws Exception {
+ PublicKey publicKey = regeneratePublicKey(publicKeyText, algorithm);
+ byte[] plainTextInBytes = plainText.getBytes(DEFAULT_CHARSET);
+ byte[] ciphertextInBytes = transform(algorithm, Cipher.ENCRYPT_MODE, publicKey, plainTextInBytes);
+ return BASE64_ENCODER.encodeToString(ciphertextInBytes);
+ }
+
+ /**
+ * 非对称解密
+ * @param privateKeyText 私钥
+ * @param ciphertext 密文
+ * @param algorithm 非对称加密算法
+ * @return
+ * @throws Exception
+ */
+ public static String decryptAsymmetrically(String privateKeyText, String ciphertext, Algorithm algorithm) throws Exception {
+ PrivateKey privateKey = regeneratePrivateKey(privateKeyText, algorithm);
+ byte[] ciphertextInBytes = BASE64_DECODER.decode(ciphertext);
+ byte[] plainTextInBytes = transform(algorithm, Cipher.DECRYPT_MODE, privateKey, ciphertextInBytes);
+ return new String(plainTextInBytes, DEFAULT_CHARSET);
+ }
+
+ /**
+ * 生成数字签名
+ * @param privateKeyText 私钥
+ * @param msg 传输的数据
+ * @param encryptionAlgorithm 加密算法,见Algorithm中的加密算法
+ * @param signatureAlgorithm 签名算法,见Algorithm中的签名算法
+ * @return 数字签名
+ * @throws Exception
+ */
+ public static String doSign(String privateKeyText, String msg, Algorithm encryptionAlgorithm, Algorithm signatureAlgorithm)
+ throws Exception {
+ PrivateKey privateKey = regeneratePrivateKey(privateKeyText, encryptionAlgorithm);
+ // Signature只支持签名算法
+ Signature signature = Signature.getInstance(signatureAlgorithm.getName());
+ signature.initSign(privateKey);
+ signature.update(msg.getBytes(DEFAULT_CHARSET));
+ byte[] signatureInBytes = signature.sign();
+ return BASE64_ENCODER.encodeToString(signatureInBytes);
+ }
+
+ /**
+ * 数字签名验证
+ * @param publicKeyText 公钥
+ * @param msg 传输的数据
+ * @param signatureText 数字签名
+ * @param encryptionAlgorithm 加密算法,见Algorithm中的加密算法
+ * @param signatureAlgorithm 签名算法,见Algorithm中的签名算法
+ * @return 校验是否成功
+ * @throws Exception
+ */
+ public static boolean doVerify(String publicKeyText, String msg, String signatureText, Algorithm encryptionAlgorithm,
+ Algorithm signatureAlgorithm) throws Exception {
+ PublicKey publicKey = regeneratePublicKey(publicKeyText, encryptionAlgorithm);
+ Signature signature = Signature.getInstance(signatureAlgorithm.getName());
+ signature.initVerify(publicKey);
+ signature.update(msg.getBytes(DEFAULT_CHARSET));
+ return signature.verify(BASE64_DECODER.decode(signatureText));
+ }
+
+ /**
+ * 将密钥进行Base64位解码,重新生成SecretKey实例
+ * @param secretKey 密钥
+ * @param algorithm 算法
+ * @return
+ */
+ private static SecretKey decodeSymmetricKey(String secretKey, Algorithm algorithm) {
+ byte[] key = BASE64_DECODER.decode(secretKey);
+ return new SecretKeySpec(key, algorithm.getName());
+ }
+
+ private static IvParameterSpec decodeIv(String iv) {
+ byte[] ivInBytes = BASE64_DECODER.decode(iv);
+ return new IvParameterSpec(ivInBytes);
+ }
+
+ private static PublicKey regeneratePublicKey(String publicKeyText, Algorithm algorithm)
+ throws NoSuchAlgorithmException, InvalidKeySpecException {
+ byte[] keyInBytes = BASE64_DECODER.decode(publicKeyText);
+ KeyFactory keyFactory = getKeyFactory(algorithm);
+ // 公钥必须使用RSAPublicKeySpec或者X509EncodedKeySpec
+ KeySpec publicKeySpec = new X509EncodedKeySpec(keyInBytes);
+ PublicKey publicKey = keyFactory.generatePublic(publicKeySpec);
+ return publicKey;
+ }
+
+ private static PrivateKey regeneratePrivateKey(String key, Algorithm algorithm) throws Exception {
+ byte[] keyInBytes = BASE64_DECODER.decode(key);
+ KeyFactory keyFactory = getKeyFactory(algorithm);
+ // 私钥必须使用RSAPrivateCrtKeySpec或者PKCS8EncodedKeySpec
+ KeySpec privateKeySpec = new PKCS8EncodedKeySpec(keyInBytes);
+ PrivateKey privateKey = keyFactory.generatePrivate(privateKeySpec);
+ return privateKey;
+ }
+
+ private static KeyFactory getKeyFactory(Algorithm algorithm) throws NoSuchAlgorithmException {
+ KeyFactory keyFactory = KEY_FACTORY_CACHE.get(algorithm);
+ if (keyFactory == null) {
+ keyFactory = KeyFactory.getInstance(algorithm.getName());
+ KEY_FACTORY_CACHE.put(algorithm, keyFactory);
+ }
+
+ return keyFactory;
+ }
+
+ private static byte[] transform(Algorithm algorithm, int mode, Key key, byte[] msg) throws Exception {
+ return transform(algorithm, mode, key, null, msg);
+ }
+
+ private static byte[] transform(Algorithm algorithm, int mode, Key key, IvParameterSpec iv, byte[] msg) throws Exception {
+ Cipher cipher = CIPHER_CACHE.get(algorithm);
+ // double check,减少上下文切换
+ if (cipher == null) {
+ synchronized (CryptoUtils.class) {
+ if ((cipher = CIPHER_CACHE.get(algorithm)) == null) {
+ cipher = determineWhichCipherToUse(algorithm);
+ CIPHER_CACHE.put(algorithm, cipher);
+ }
+ cipher.init(mode, key, iv);
+ return cipher.doFinal(msg);
+ }
+ }
+
+ synchronized (CryptoUtils.class) {
+ cipher.init(mode, key, iv);
+ return cipher.doFinal(msg);
+ }
+ }
+
+ private static Cipher determineWhichCipherToUse(Algorithm algorithm) throws NoSuchAlgorithmException, NoSuchPaddingException {
+ Cipher cipher;
+ String transformation = algorithm.getTransformation();
+ // 官方推荐的transformation使用algorithm/mode/padding组合,SunJCE使用ECB作为默认模式,使用PKCS5Padding作为默认填充
+ if (StringUtils.isNotEmpty(transformation)) {
+ cipher = Cipher.getInstance(transformation);
+ } else {
+ cipher = Cipher.getInstance(algorithm.getName());
+ }
+
+ return cipher;
+ }
+
+ /**
+ * 算法分为加密算法和签名算法,更多算法实现见:
+ * jdk8中的标准算法
+ */
+ public static class Algorithm {
+
+ public interface Encryption {
+ Algorithm AES_ECB_PKCS5 = new Algorithm("AES", "AES/ECB/PKCS5Padding", 128);
+ Algorithm AES_CBC_PKCS5 = new Algorithm("AES", "AES/CBC/PKCS5Padding", 128);
+ Algorithm DES_ECB_PKCS5 = new Algorithm("DES", "DES/ECB/PKCS5Padding", 56);
+ Algorithm DES_CBC_PKCS5 = new Algorithm("DES", "DES/CBC/PKCS5Padding", 56);
+ Algorithm RSA_ECB_PKCS1 = new Algorithm("RSA", "RSA/ECB/PKCS1Padding", 1024);
+ Algorithm DSA = new Algorithm("DSA", 1024);
+ }
+
+ public interface Signing {
+ Algorithm SHA1WithDSA = new Algorithm("SHA1withDSA", 1024);
+ Algorithm SHA1WithRSA = new Algorithm("SHA1WithRSA", 2048);
+ Algorithm SHA256WithRSA = new Algorithm("SHA256WithRSA", 2048);
+ }
+
+ @Getter
+ private String name;
+ @Getter
+ private String transformation;
+ @Getter
+ private int keySize;
+
+ public Algorithm(String name, int keySize) {
+ this(name, null, keySize);
+ }
+
+ public Algorithm(String name, String transformation, int keySize) {
+ this.name = name;
+ this.transformation = transformation;
+ this.keySize = keySize;
+ }
+
+ }
+
+ @Data
+ @NoArgsConstructor
+ @AllArgsConstructor
+ public static class AsymmetricKeyPair {
+
+ private String publicKey;
+ private String privateKey;
+ }
+
+}
+
+
+