Merge remote-tracking branch 'origin/competition' into deployment_gateway_20240416

# Conflicts:
#	pom.xml
#	sf-admin/pom.xml
#	sf-admin/src/main/resources/application.yml
#	sf-service/pom.xml
#	sf-system/src/main/java/com/sf/system/deployment/controller/DeploymentApplyEnvironmentController.java
#	sf-system/src/main/java/com/sf/system/deployment/controller/DeploymentServicePublishController.java
#	sf-system/src/main/java/com/sf/system/deployment/domain/DeploymentApplyEnvironment.java
#	sf-system/src/main/java/com/sf/system/deployment/domain/DeploymentServicePublish.java
#	sf-system/src/main/java/com/sf/system/deployment/mapper/DeploymentApplyEnvironmentMapper.java
#	sf-system/src/main/java/com/sf/system/deployment/service/IDeploymentApplyEnvironmentService.java
#	sf-system/src/main/java/com/sf/system/deployment/service/IDeploymentServicePublishService.java
#	sf-system/src/main/java/com/sf/system/deployment/service/impl/DeploymentApplyEnvironmentServiceImpl.java
#	sf-system/src/main/java/com/sf/system/deployment/service/impl/DeploymentServicePublishServiceImpl.java
#	sf-system/src/main/resources/mapper/system/deployment/DeploymentApplyEnvironmentMapper.xml
#	sf-system/src/main/resources/mapper/system/deployment/DeploymentServicePublishMapper.xml
#	sf-ui/package.json
#	sf-ui/src/api/FDS/whiteList.js
#	sf-ui/src/api/deploy/INFO.js
#	sf-ui/src/api/deployment/publish.js
#	sf-ui/src/components/FileUpload/index.vue
#	sf-ui/src/components/ImageUpload/index.vue
#	sf-ui/src/store/modules/permission.js
#	sf-ui/src/store/modules/user.js
#	sf-ui/src/utils/application.js
#	sf-ui/src/utils/request.js
#	sf-ui/src/views/FDS/installationList/add.vue
#	sf-ui/src/views/FDS/installationList/detail.vue
#	sf-ui/src/views/FDS/installationList/edit.vue
#	sf-ui/src/views/FDS/installationList/index.vue
#	sf-ui/src/views/FDS/publishList/components/addPack.vue
#	sf-ui/src/views/FDS/publishList/index.vue
#	sf-ui/src/views/FDS/whiteListManagement/add.vue
#	sf-ui/src/views/FDS/whiteListManagement/edit.vue
#	sf-ui/src/views/FDS/whiteListManagement/index.vue
#	sf-ui/src/views/deploy/INFO/add.vue
#	sf-ui/src/views/deployment/publish/index.vue
#	sf-ui/src/views/indexNew.vue
#	sf-ui/src/views/service/goods/index.vue
#	sf-ui/vue.config.js
This commit is contained in:
akun 2024-05-10 14:21:47 +08:00
commit 3a6b90197c
166 changed files with 12661 additions and 1033 deletions

8
Dockerfile Normal file
View File

@ -0,0 +1,8 @@
FROM openjdk:8
# 复制jar文件到路径
COPY ./sf-admin/target/sf-admin.jar /usr/local/sf-admin.jar
RUN /bin/cp /usr/share/zoneinfo/Asia/Shanghai /etc/localtime && echo 'Asia/Shanghai' >/etc/timezone
# 指定路径
WORKDIR /usr/local
ENTRYPOINT ["java","-jar","sf-admin.jar"]

34
pom.xml
View File

@ -147,12 +147,6 @@
<version>${sf.version}</version>
</dependency>
<dependency>
<groupId>com.smarterFramework</groupId>
<artifactId>sf-service</artifactId>
<version>${sf.version}</version>
</dependency>
<!-- 核心模块-->
<dependency>
<groupId>com.smarterFramework</groupId>
@ -167,6 +161,30 @@
<version>${sf.version}</version>
</dependency>
<!-- 三方授权模块-->
<dependency>
<groupId>com.smarterFramework</groupId>
<artifactId>sf-oauth</artifactId>
<version>${sf.version}</version>
</dependency>
<dependency>
<groupId>com.smarterFramework</groupId>
<artifactId>sf-order</artifactId>
<version>${sf.version}</version>
</dependency>
<dependency>
<groupId>com.smarterFramework</groupId>
<artifactId>sf-payment</artifactId>
<version>${sf.version}</version>
</dependency>
<dependency>
<groupId>com.smarterFramework</groupId>
<artifactId>sf-service</artifactId>
<version>${sf.version}</version>
</dependency>
<!-- 通用工具-->
<dependency>
<groupId>com.smarterFramework</groupId>
@ -211,6 +229,10 @@
<module>sf-file</module>
<module>sf-common</module>
<module>sf-apijson</module>
<module>sf-oauth</module>
<module>sf-payment</module>
<module>sf-service</module>
<module>sf-order</module>
<module>sf-vertx</module>
<module>sf-vertx-api</module>
<module>sf-service</module>

View File

@ -61,6 +61,21 @@
<artifactId>sf-file</artifactId>
</dependency>
<dependency>
<groupId>com.smarterFramework</groupId>
<artifactId>sf-oauth</artifactId>
</dependency>
<dependency>
<groupId>com.smarterFramework</groupId>
<artifactId>sf-order</artifactId>
</dependency>
<dependency>
<groupId>com.smarterFramework</groupId>
<artifactId>sf-payment</artifactId>
</dependency>
<!-- 业务模块-->
<dependency>
<groupId>com.smarterFramework</groupId>

View File

@ -0,0 +1,107 @@
package com.sf.index.controller;
import java.util.List;
import javax.servlet.http.HttpServletResponse;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.PutMapping;
import org.springframework.web.bind.annotation.DeleteMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import com.sf.common.annotation.Log;
import com.sf.common.core.controller.BaseController;
import com.sf.common.core.domain.AjaxResult;
import com.sf.common.enums.BusinessType;
import com.sf.index.domain.ApplyListInfo;
import com.sf.index.service.IApplyListInfoService;
import com.sf.common.utils.poi.ExcelUtil;
import com.sf.common.core.page.TableDataInfo;
/**
* 应用列Controller
*
* @author ztzh
* @date 2024-04-11
*/
@RestController
@RequestMapping("/index/list")
public class ApplyListInfoController extends BaseController
{
@Autowired
private IApplyListInfoService applyListInfoService;
/**
* 查询应用列列表
*/
@PreAuthorize("@ss.hasPermi('index:list:list')")
@GetMapping("/list")
public TableDataInfo list(ApplyListInfo applyListInfo)
{
startPage();
List<ApplyListInfo> list = applyListInfoService.selectApplyListInfoList(applyListInfo);
return getDataTable(list);
}
/**
* 导出应用列列表
*/
@PreAuthorize("@ss.hasPermi('index:list:export')")
@Log(title = "应用列", businessType = BusinessType.EXPORT)
@PostMapping("/export")
public void export(HttpServletResponse response, ApplyListInfo applyListInfo)
{
List<ApplyListInfo> list = applyListInfoService.selectApplyListInfoList(applyListInfo);
ExcelUtil<ApplyListInfo> util = new ExcelUtil<ApplyListInfo>(ApplyListInfo.class);
util.exportExcel(response, list, "应用列数据");
}
/**
* 获取应用列详细信息
*/
@PreAuthorize("@ss.hasPermi('index:list:query')")
@GetMapping(value = "/{id}")
public AjaxResult getInfo(@PathVariable("id") Long id)
{
return success(applyListInfoService.selectApplyListInfoById(id));
}
/**
* 新增应用列
*/
@PreAuthorize("@ss.hasPermi('index:list:add')")
@Log(title = "应用列", businessType = BusinessType.INSERT)
@PostMapping
public AjaxResult add(@RequestBody ApplyListInfo applyListInfo)
{
applyListInfo.setCreated(getUsername());
applyListInfo.setModified(getUsername());
return toAjax(applyListInfoService.insertApplyListInfo(applyListInfo));
}
/**
* 修改应用列
*/
@PreAuthorize("@ss.hasPermi('index:list:edit')")
@Log(title = "应用列", businessType = BusinessType.UPDATE)
@PutMapping
public AjaxResult edit(@RequestBody ApplyListInfo applyListInfo)
{
applyListInfo.setModified(getUsername());
return toAjax(applyListInfoService.updateApplyListInfo(applyListInfo));
}
/**
* 删除应用列
*/
@PreAuthorize("@ss.hasPermi('index:list:remove')")
@Log(title = "应用列", businessType = BusinessType.DELETE)
@DeleteMapping("/{ids}")
public AjaxResult remove(@PathVariable Long[] ids)
{
return toAjax(applyListInfoService.deleteApplyListInfoByIds(ids));
}
}

View File

@ -0,0 +1,153 @@
package com.sf.index.domain;
import org.apache.commons.lang3.builder.ToStringBuilder;
import org.apache.commons.lang3.builder.ToStringStyle;
import com.sf.common.annotation.Excel;
import com.sf.common.core.domain.BaseEntity;
/**
* 应用列对象 APPLY_LIST_INFO
*
* @author ztzh
* @date 2024-04-11
*/
public class ApplyListInfo extends BaseEntity {
private static final long serialVersionUID = 1L;
/**
* 主键
*/
private Long id;
/**
* 应用code
*/
@Excel(name = "应用编号")
private String appCode;
/**
* 应用名称
*/
@Excel(name = "应用名称")
private String appName;
/**
* 应用描述
*/
@Excel(name = "应用描述")
private String appDesc;
/**
* 图片
*/
@Excel(name = "图片")
private String picture;
/**
* 排序
*/
private Long orderNum;
/**
* 逻辑删除,0:未删除,1:删除
*/
private Long isDelete;
/**
* 创建人
*/
private String created;
/**
* 更新人
*/
private String modified;
public void setId(Long id) {
this.id = id;
}
public Long getId() {
return id;
}
public void setAppName(String appName) {
this.appName = appName;
}
public String getAppName() {
return appName;
}
public void setAppDesc(String appDesc) {
this.appDesc = appDesc;
}
public String getAppDesc() {
return appDesc;
}
public void setPicture(String picture) {
this.picture = picture;
}
public String getPicture() {
return picture;
}
public void setOrderNum(Long orderNum) {
this.orderNum = orderNum;
}
public Long getOrderNum() {
return orderNum;
}
public void setIsDelete(Long isDelete) {
this.isDelete = isDelete;
}
public Long getIsDelete() {
return isDelete;
}
public void setCreated(String created) {
this.created = created;
}
public String getCreated() {
return created;
}
public void setModified(String modified) {
this.modified = modified;
}
public String getModified() {
return modified;
}
public void setAppCode(String appCode) {
this.appCode = appCode;
}
public String getAppCode() {
return appCode;
}
@Override
public String toString() {
return new ToStringBuilder(this, ToStringStyle.MULTI_LINE_STYLE)
.append("id", getId())
.append("appCode",getAppCode())
.append("appName", getAppName())
.append("appDesc", getAppDesc())
.append("picture", getPicture())
.append("orderNum", getOrderNum())
.append("isDelete", getIsDelete())
.append("created", getCreated())
.append("modified", getModified())
.append("createTime", getCreateTime())
.append("updateTime", getUpdateTime())
.toString();
}
}

View File

@ -0,0 +1,61 @@
package com.sf.index.mapper;
import java.util.List;
import com.sf.index.domain.ApplyListInfo;
/**
* 应用列Mapper接口
*
* @author ztzh
* @date 2024-04-11
*/
public interface ApplyListInfoMapper
{
/**
* 查询应用列
*
* @param id 应用列主键
* @return 应用列
*/
public ApplyListInfo selectApplyListInfoById(Long id);
/**
* 查询应用列列表
*
* @param applyListInfo 应用列
* @return 应用列集合
*/
public List<ApplyListInfo> selectApplyListInfoList(ApplyListInfo applyListInfo);
/**
* 新增应用列
*
* @param applyListInfo 应用列
* @return 结果
*/
public int insertApplyListInfo(ApplyListInfo applyListInfo);
/**
* 修改应用列
*
* @param applyListInfo 应用列
* @return 结果
*/
public int updateApplyListInfo(ApplyListInfo applyListInfo);
/**
* 删除应用列
*
* @param id 应用列主键
* @return 结果
*/
public int deleteApplyListInfoById(Long id);
/**
* 批量删除应用列
*
* @param ids 需要删除的数据主键集合
* @return 结果
*/
public int deleteApplyListInfoByIds(Long[] ids);
}

View File

@ -0,0 +1,61 @@
package com.sf.index.service;
import java.util.List;
import com.sf.index.domain.ApplyListInfo;
/**
* 应用列Service接口
*
* @author ztzh
* @date 2024-04-11
*/
public interface IApplyListInfoService
{
/**
* 查询应用列
*
* @param id 应用列主键
* @return 应用列
*/
public ApplyListInfo selectApplyListInfoById(Long id);
/**
* 查询应用列列表
*
* @param applyListInfo 应用列
* @return 应用列集合
*/
public List<ApplyListInfo> selectApplyListInfoList(ApplyListInfo applyListInfo);
/**
* 新增应用列
*
* @param applyListInfo 应用列
* @return 结果
*/
public int insertApplyListInfo(ApplyListInfo applyListInfo);
/**
* 修改应用列
*
* @param applyListInfo 应用列
* @return 结果
*/
public int updateApplyListInfo(ApplyListInfo applyListInfo);
/**
* 批量删除应用列
*
* @param ids 需要删除的应用列主键集合
* @return 结果
*/
public int deleteApplyListInfoByIds(Long[] ids);
/**
* 删除应用列信息
*
* @param id 应用列主键
* @return 结果
*/
public int deleteApplyListInfoById(Long id);
}

View File

@ -0,0 +1,98 @@
package com.sf.index.service.impl;
import java.util.List;
import com.sf.common.utils.DateUtils;
import com.sf.common.utils.uuid.IdUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import com.sf.index.mapper.ApplyListInfoMapper;
import com.sf.index.domain.ApplyListInfo;
import com.sf.index.service.IApplyListInfoService;
/**
* 应用列Service业务层处理
*
* @author ztzh
* @date 2024-04-11
*/
@Service
public class ApplyListInfoServiceImpl implements IApplyListInfoService
{
@Autowired
private ApplyListInfoMapper applyListInfoMapper;
/**
* 查询应用列
*
* @param id 应用列主键
* @return 应用列
*/
@Override
public ApplyListInfo selectApplyListInfoById(Long id)
{
return applyListInfoMapper.selectApplyListInfoById(id);
}
/**
* 查询应用列列表
*
* @param applyListInfo 应用列
* @return 应用列
*/
@Override
public List<ApplyListInfo> selectApplyListInfoList(ApplyListInfo applyListInfo)
{
return applyListInfoMapper.selectApplyListInfoList(applyListInfo);
}
/**
* 新增应用列
*
* @param applyListInfo 应用列
* @return 结果
*/
@Override
public int insertApplyListInfo(ApplyListInfo applyListInfo)
{
applyListInfo.setCreateTime(DateUtils.getNowDate());
applyListInfo.setAppCode(IdUtils.randomTime("ZT"));
return applyListInfoMapper.insertApplyListInfo(applyListInfo);
}
/**
* 修改应用列
*
* @param applyListInfo 应用列
* @return 结果
*/
@Override
public int updateApplyListInfo(ApplyListInfo applyListInfo)
{
applyListInfo.setUpdateTime(DateUtils.getNowDate());
return applyListInfoMapper.updateApplyListInfo(applyListInfo);
}
/**
* 批量删除应用列
*
* @param ids 需要删除的应用列主键
* @return 结果
*/
@Override
public int deleteApplyListInfoByIds(Long[] ids)
{
return applyListInfoMapper.deleteApplyListInfoByIds(ids);
}
/**
* 删除应用列信息
*
* @param id 应用列主键
* @return 结果
*/
@Override
public int deleteApplyListInfoById(Long id)
{
return applyListInfoMapper.deleteApplyListInfoById(id);
}
}

View File

@ -88,6 +88,7 @@ public class CommonController
ajax.put("fileName", fileName);
ajax.put("newFileName", FileUtils.getName(fileName));
ajax.put("originalFilename", file.getOriginalFilename());
ajax.put("fileSize", file.getSize());
return ajax;
}
catch (Exception e)
@ -95,7 +96,6 @@ public class CommonController
return AjaxResult.error(e.getMessage());
}
}
/**
* 通用上传请求多个
*/

View File

@ -49,8 +49,8 @@ public class SysLoginController
{
AjaxResult ajax = AjaxResult.success();
// 生成令牌
String token = loginService.login(loginBody.getUsername(), loginBody.getPassword(), loginBody.getCode(),
loginBody.getUuid(), session);
String token = loginService.login(loginBody.getUsername(), loginBody.getPassword(),
loginBody.getCode(),loginBody.getUuid(), session);
ajax.put(Constants.TOKEN, token);
return ajax;
}

View File

@ -36,6 +36,7 @@ import com.sf.system.service.ISysUserService;
/**
* 用户信息
*
*
* @author ztzh
*/
@RestController

View File

@ -0,0 +1,117 @@
package com.sf.web.controller.system;
import java.util.List;
import javax.servlet.http.HttpServletResponse;
import com.sf.common.utils.SecurityUtils;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.PutMapping;
import org.springframework.web.bind.annotation.DeleteMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import com.sf.common.annotation.Log;
import com.sf.common.core.controller.BaseController;
import com.sf.common.core.domain.AjaxResult;
import com.sf.common.enums.BusinessType;
import com.sf.system.domain.UserMember;
import com.sf.system.service.IUserMemberService;
import com.sf.common.utils.poi.ExcelUtil;
import com.sf.common.core.page.TableDataInfo;
/**
* 会员Controller
*
* @author ztzh
* @date 2024-04-16
*/
@RestController
@RequestMapping("/system/member")
public class UserMemberController extends BaseController
{
@Autowired
private IUserMemberService userMemberService;
/**
* 查询会员列表
*/
@PreAuthorize("@ss.hasPermi('system:member:list')")
@GetMapping("/list")
public TableDataInfo list(UserMember userMember)
{
startPage();
List<UserMember> list = userMemberService.selectUserMemberList(userMember);
return getDataTable(list);
}
/**
* 导出会员列表
*/
@PreAuthorize("@ss.hasPermi('system:member:export')")
@Log(title = "会员", businessType = BusinessType.EXPORT)
@PostMapping("/export")
public void export(HttpServletResponse response, UserMember userMember)
{
List<UserMember> list = userMemberService.selectUserMemberList(userMember);
ExcelUtil<UserMember> util = new ExcelUtil<UserMember>(UserMember.class);
util.exportExcel(response, list, "会员数据");
}
/**
* 获取会员详细信息
*/
@PreAuthorize("@ss.hasPermi('system:member:query')")
@GetMapping(value = "/{id}")
public AjaxResult getInfo(@PathVariable("id") Long id)
{
return success(userMemberService.selectUserMemberById(id));
}
/**
* 获取会员详细信息,通过用户id
* 当前用户
*/
@GetMapping(value = "/currentUser")
public AjaxResult getInfoByUser()
{
Long userId = SecurityUtils.getUserId();
return success(userMemberService.selectUserMemberByUserId(userId));
}
/**
* 新增会员
*/
@PreAuthorize("@ss.hasPermi('system:member:add')")
@Log(title = "会员", businessType = BusinessType.INSERT)
@PostMapping
public AjaxResult add(@RequestBody UserMember userMember)
{
return toAjax(userMemberService.insertUserMember(userMember));
}
/**
* 修改会员
*/
@PreAuthorize("@ss.hasPermi('system:member:edit')")
@Log(title = "会员", businessType = BusinessType.UPDATE)
@PutMapping
public AjaxResult edit(@RequestBody UserMember userMember)
{
return toAjax(userMemberService.updateUserMember(userMember));
}
/**
* 删除会员
*/
@PreAuthorize("@ss.hasPermi('system:member:remove')")
@Log(title = "会员", businessType = BusinessType.DELETE)
@DeleteMapping("/{ids}")
public AjaxResult remove(@PathVariable Long[] ids)
{
return toAjax(userMemberService.deleteUserMemberByIds(ids));
}
}

View File

@ -6,9 +6,9 @@ spring:
druid:
# 主库数据源
master:
url: jdbc:mysql://192.168.1.23:22001/sac?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=GMT%2B8
url: jdbc:mysql://47.108.66.163:3306/sac_competition?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=GMT%2B8
username: root
password: abc&^321
password: 82^hsgGHbs^2
# 从库数据源
slave:
# 从数据源开关/默认关闭

View File

@ -59,9 +59,9 @@ spring:
servlet:
multipart:
# 单个文件大小
max-file-size: 10MB
max-file-size: 100MB
# 设置总上传的文件大小
max-request-size: 20MB
max-request-size: 200MB
# 服务模块
devtools:
restart:

View File

@ -0,0 +1,20 @@
-----BEGIN CERTIFICATE-----
MIIDSDCCAjACCQCvqL+z6dKTrjANBgkqhkiG9w0BAQsFADBmMQswCQYDVQQGEwJD
TjERMA8GA1UECAwIc2hpY2h1YW4xEDAOBgNVBAcMB2NoZW5nZHUxEjAQBgNVBAoM
CXpob25ndGlhbjEKMAgGA1UECwwBQjESMBAGA1UEAwwJemhvbmd0aWFuMB4XDTI0
MDQxNzA2MjIxNloXDTI1MDQxNzA2MjIxNlowZjELMAkGA1UEBhMCQ04xETAPBgNV
BAgMCHNoaWNodWFuMRAwDgYDVQQHDAdjaGVuZ2R1MRIwEAYDVQQKDAl6aG9uZ3Rp
YW4xCjAIBgNVBAsMAUIxEjAQBgNVBAMMCXpob25ndGlhbjCCASIwDQYJKoZIhvcN
AQEBBQADggEPADCCAQoCggEBAMIXQc0iVEuN/c8PnryNQYP3WbF6irqnjTbk/kCV
552p30ZmdeRDGcFKdkohQLKT06sbqlaBzhGFpnLlb5iz1dG1sGZbw064RFZRlgED
P7ROP891dvj9scPxfWC1Moy6/9LXBQLIshD7zTxzOemqxdyJ1jELianrWWm4XFKM
jvl7BGcfS/VIEafrJ5WGzuRMKtf6SY8aD5Olu0sN61tnSIgjWwZnKkv4V764UBpN
ybTsk1ctefUNMkE5Q+b2gu+0i5qH18B5/H5O7oAEAA+IWIPxIzuINnAYvHRhNQ/W
LMaI/GhYpQMhlmXtOmFFFe3fL4fKRMCKa3x2Va/GzfPjwecCAwEAATANBgkqhkiG
9w0BAQsFAAOCAQEAZmqK3ZfCA3A99VRfSRmCnpBbAW7SIxNeRqKFa5dunOMb7R6B
+bV/ALLJmu8S5D7pSR/wqCGURmnetUnBAEQmYJsjSq3142PeADkr8NmZ9bOXBVNM
szfSPOeM8HCUVjG9r+VMuy6yuPXFzp6QcKC13pzdziMdTHyKSu25fbYwE3lYOXk9
4nLpnJeT09gecXPdGllrVTKkgkE7L7h4iX/QzsGiZ/JbrCD77nPFqr7fkepsrHjl
4U1Pfjc3NStquhT5ZINDr7MBg/JaHNW57ynt1ud0y1lUOu2o5fpmyYVy/4llRl+T
VJ6mJYXIWr+i10bVjNv2tGPEylmI1JHelYRqAQ==
-----END CERTIFICATE-----

View File

@ -0,0 +1,92 @@
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.sf.index.mapper.ApplyListInfoMapper">
<resultMap type="ApplyListInfo" id="ApplyListInfoResult">
<result property="id" column="id" />
<result property="appCode" column="app_code" />
<result property="appName" column="app_name" />
<result property="appDesc" column="app_desc" />
<result property="picture" column="picture" />
<result property="orderNum" column="order_num" />
<result property="isDelete" column="is_delete" />
<result property="created" column="created" />
<result property="modified" column="modified" />
<result property="createTime" column="create_time" />
<result property="updateTime" column="update_time" />
</resultMap>
<sql id="selectApplyListInfoVo">
select id, app_code, app_name, app_desc, picture, order_num, is_delete, created, modified, create_time, update_time from APPLY_LIST_INFO
</sql>
<select id="selectApplyListInfoList" parameterType="ApplyListInfo" resultMap="ApplyListInfoResult">
<include refid="selectApplyListInfoVo"/>
<where>
<if test="appName != null and appName != ''"> and app_name like concat('%', #{appName}, '%')</if>
</where>
</select>
<select id="selectApplyListInfoById" parameterType="Long" resultMap="ApplyListInfoResult">
<include refid="selectApplyListInfoVo"/>
where id = #{id}
</select>
<insert id="insertApplyListInfo" parameterType="ApplyListInfo" useGeneratedKeys="true" keyProperty="id">
insert into APPLY_LIST_INFO
<trim prefix="(" suffix=")" suffixOverrides=",">
<if test="appCode != null and appCode != ''">app_code,</if>
<if test="appName != null and appName != ''">app_name,</if>
<if test="appDesc != null and appDesc != ''">app_desc,</if>
<if test="picture != null">picture,</if>
<if test="orderNum != null">order_num,</if>
<if test="isDelete != null">is_delete,</if>
<if test="created != null">created,</if>
<if test="modified != null">modified,</if>
<if test="createTime != null">create_time,</if>
<if test="updateTime != null">update_time,</if>
</trim>
<trim prefix="values (" suffix=")" suffixOverrides=",">
<if test="appCode != null and appCode != ''">#{appCode},</if>
<if test="appName != null and appName != ''">#{appName},</if>
<if test="appDesc != null and appDesc != ''">#{appDesc},</if>
<if test="picture != null">#{picture},</if>
<if test="orderNum != null">#{orderNum},</if>
<if test="isDelete != null">#{isDelete},</if>
<if test="created != null">#{created},</if>
<if test="modified != null">#{modified},</if>
<if test="createTime != null">#{createTime},</if>
<if test="updateTime != null">#{updateTime},</if>
</trim>
</insert>
<update id="updateApplyListInfo" parameterType="ApplyListInfo">
update APPLY_LIST_INFO
<trim prefix="SET" suffixOverrides=",">
<if test="appCode != null and appCode != ''">app_code = #{appCode},</if>
<if test="appName != null and appName != ''">app_name = #{appName},</if>
<if test="appDesc != null and appDesc != ''">app_desc = #{appDesc},</if>
<if test="picture != null">picture = #{picture},</if>
<if test="orderNum != null">order_num = #{orderNum},</if>
<if test="isDelete != null">is_delete = #{isDelete},</if>
<if test="created != null">created = #{created},</if>
<if test="modified != null">modified = #{modified},</if>
<if test="createTime != null">create_time = #{createTime},</if>
<if test="updateTime != null">update_time = #{updateTime},</if>
</trim>
where id = #{id}
</update>
<delete id="deleteApplyListInfoById" parameterType="Long">
delete from APPLY_LIST_INFO where id = #{id}
</delete>
<delete id="deleteApplyListInfoByIds" parameterType="String">
delete from APPLY_LIST_INFO where id in
<foreach item="id" collection="array" open="(" separator="," close=")">
#{id}
</foreach>
</delete>
</mapper>

View File

@ -15,6 +15,17 @@
<dependencies>
<!-- 生成二维码 -->
<dependency>
<groupId>net.glxn.qrgen</groupId>
<artifactId>javase</artifactId>
<version>2.0</version>
</dependency> <!-- Spring框架基本的核心工具 -->
<dependency>
<groupId>commons-fileupload</groupId>
<artifactId>commons-fileupload</artifactId>
<version>1.4</version>
</dependency>
<!-- Spring框架基本的核心工具 -->
<dependency>
<groupId>org.springframework</groupId>

View File

@ -0,0 +1,47 @@
package com.sf.common.enums;
import java.util.HashMap;
import java.util.Map;
/**
* header参数
*
* @author ztzh
*
*/
public enum RequestHeaderEnums
{
/**
* 通知完成指令用于客户端收到通知消息的确认
*/
APP_CODE("appCode"),
/**
* 通知完成指令用于客户端收到通知消息的确认 Authorization
*/
AUTHORIZATION("Authorization"),
;
private static Map<String, RequestHeaderEnums> map = new HashMap<>();
static {
for (RequestHeaderEnums type : RequestHeaderEnums.values()) {
map.put(type.code, type);
}
}
private String code;
RequestHeaderEnums(String code) {
this.code = code;
}
public String getCode() {
return code;
}
public static final RequestHeaderEnums getByCode(String code) {
return map.get(code);
}
}

View File

@ -0,0 +1,152 @@
package com.sf.common.utils;
import org.springframework.stereotype.Component;
/**
* Tiwtter.SnowFlake的结构如下(每部分用-分开):<br>
* 0 - 0000000000 0000000000 0000000000 0000000000 0 - 00000 - 00000 - 000000000000 <br>
* 1位标识由于long基本类型在Java中是带符号的最高位是符号位正数是0负数是1所以id一般是正数最高位是0<br>
* 41位时间截(毫秒级)注意41位时间截不是存储当前时间的时间截而是存储时间截的差值当前时间截 - 开始时间截)
* 得到的值这里的的开始时间截一般是我们的id生成器开始使用的时间由我们程序来指定的如下下面程序IdWorker类的startTime属性41位的时间截可以使用69年年T = (1L << 41) / (1000L * 60 * 60 * 24 * 365) = 69<br>
* 10位的数据机器位可以部署在1024个节点包括5位datacenterId和5位workerId<br>
* 12位序列毫秒内的计数12位的计数顺序号支持每个节点每毫秒(同一机器同一时间截)产生4096个ID序号<br>
* 加起来刚好64位为一个Long型<br>
* SnowFlake的优点是整体上按照时间自增排序并且整个分布式系统内不会产生ID碰撞(由数据中心ID和机器ID作区分)并且效率较高经测试SnowFlake每秒能够产生26万ID左右
* @author yswjme@163.com
* @date :
*
*/
@Component
public class SnowflakeIdWorker {
/** 开始时间截 (2018-01-01) ,不可修改 */
private final long twepoch = 1420041600000L;
/** 机器id所占的位数 */
private final long workerIdBits = 5L;
/** 数据标识id所占的位数 */
private final long datacenterIdBits = 5L;
/** 支持的最大机器id结果是31 (这个移位算法可以很快的计算出几位二进制数所能表示的最大十进制数) */
private final long maxWorkerId = -1L ^ (-1L << workerIdBits);
/** 支持的最大数据标识id结果是31 */
private final long maxDatacenterId = -1L ^ (-1L << datacenterIdBits);
/** 序列在id中占的位数 */
private final long sequenceBits = 12L;
/** 机器ID向左移12位 */
private final long workerIdShift = sequenceBits;
/** 数据标识id向左移17位(12+5) */
private final long datacenterIdShift = sequenceBits + workerIdBits;
/** 时间截向左移22位(5+5+12) */
private final long timestampLeftShift = sequenceBits + workerIdBits + datacenterIdBits;
/** 生成序列的掩码这里为4095 (0b111111111111=0xfff=4095) */
private final long sequenceMask = -1L ^ (-1L << sequenceBits);
/** 工作机器ID(0~31) */
private long workerId;
/** 数据中心ID(0~31) */
private long datacenterId;
/** 毫秒内序列(0~4095) */
private long sequence = 0L;
/** 上次生成ID的时间截 */
private long lastTimestamp = -1L;
/**
* 构造函数
*
* @param workerId 工作ID (0~31)
* @param datacenterId 数据中心ID (0~31)
*/
public SnowflakeIdWorker(long workerId, long datacenterId) {
if (workerId > maxWorkerId || workerId < 0) {
throw new IllegalArgumentException(String.format(
"worker Id can't be greater than %d or less than 0",
maxWorkerId));
}
if (datacenterId > maxDatacenterId || datacenterId < 0) {
throw new IllegalArgumentException(String.format(
"datacenter Id can't be greater than %d or less than 0",
maxDatacenterId));
}
this.workerId = workerId;
this.datacenterId = datacenterId;
}
public SnowflakeIdWorker() {
};
/**
* 获得下一个ID (该方法是线程安全的)
*
* @return SnowflakeId
*/
public synchronized long nextId() {
long timestamp = timeGen();
// 如果当前时间小于上一次ID生成的时间戳说明系统时钟回退过这个时候应当抛出异常
if (timestamp < lastTimestamp) {
throw new RuntimeException(
String.format(
"Clock moved backwards. Refusing to generate id for %d milliseconds",
lastTimestamp - timestamp));
}
// 如果是同一时间生成的则进行毫秒内序列
if (lastTimestamp == timestamp) {
sequence = (sequence + 1) & sequenceMask;
// 毫秒内序列溢出
if (sequence == 0) {
// 阻塞到下一个毫秒,获得新的时间戳
timestamp = tilNextMillis(lastTimestamp);
}
}else {// 时间戳改变毫秒内序列重置
sequence = 0L;
}
// 上次生成ID的时间截
lastTimestamp = timestamp;
// 移位并通过或运算拼到一起组成64位的ID
return ((timestamp - twepoch) << timestampLeftShift) //
| (datacenterId << datacenterIdShift) //
| (workerId << workerIdShift) //
| sequence;
}
/**
* 阻塞到下一个毫秒直到获得新的时间戳
*
* @param lastTimestamp
* 上次生成ID的时间截
* @return 当前时间戳
*/
protected long tilNextMillis(long lastTimestamp) {
long timestamp = timeGen();
while (timestamp <= lastTimestamp) {
timestamp = timeGen();
}
return timestamp;
}
/**
* 返回以毫秒为单位的当前时间
*
* @return 当前时间(毫秒)
*/
protected long timeGen() {
return System.currentTimeMillis();
}
}

View File

@ -6,25 +6,27 @@ import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.UnsupportedEncodingException;
import java.net.HttpURLConnection;
import java.net.URL;
import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.apache.commons.fileupload.FileItem;
import org.apache.commons.fileupload.FileItemFactory;
import org.apache.commons.fileupload.disk.DiskFileItemFactory;
import org.apache.commons.io.IOUtils;
import org.apache.commons.lang3.ArrayUtils;
import com.sf.common.config.SmarterFrameworkConfig;
import com.sf.common.exception.ServiceException;
import com.sf.common.utils.DateUtils;
import com.sf.common.utils.StringUtils;
import com.sf.common.utils.uuid.IdUtils;
import org.apache.commons.io.FilenameUtils;
import org.springframework.web.multipart.MultipartFile;
import org.springframework.web.multipart.commons.CommonsMultipartFile;
/**
* 文件处理工具类
@ -295,5 +297,55 @@ public class FileUtils
String baseName = FilenameUtils.getBaseName(fileName);
return baseName;
}
/**
* 根据OutputStream生成文件
*/
public static MultipartFile outputToFile(ByteArrayOutputStream bos) throws IOException {
try {
// 文件输出流
byte[] bytes = bos.toByteArray();
FileItemFactory factory = new DiskFileItemFactory(16, null);
FileItem item = factory.createItem("file", "application/zip", false, "apk.zip");
OutputStream os = item.getOutputStream();
os.write(bytes);
bos.flush();
os.flush();
// MultipartFile
MultipartFile file = new CommonsMultipartFile(item);
return file;
} catch (Exception e) {
System.err.println("加载私钥失败");
}
return null;
}
public static MultipartFile fileToMultipartFile(File file) throws IOException {
try {
FileInputStream fis = new FileInputStream(file);
ByteArrayOutputStream baos = new ByteArrayOutputStream(fis.available());
byte[] bytes = new byte[fis.available()];
int temp;
while ((temp = fis.read(bytes)) != -1) {
baos.write(bytes, 0, temp);
}
// 文件输出流
FileItemFactory factory = new DiskFileItemFactory(16, null);
FileItem item = factory.createItem("image", "image/png", false, "123.png");
OutputStream os = item.getOutputStream();
os.write(bytes);
fis.close();
baos.close();
os.flush();
// MultipartFile
MultipartFile multipartFile = new CommonsMultipartFile(item);
return multipartFile;
} catch (Exception e) {
System.err.println("二维码转换异常");
}
return null;
}
}

View File

@ -0,0 +1,18 @@
package com.sf.common.utils.file;
import net.glxn.qrgen.core.image.ImageType;
import net.glxn.qrgen.javase.QRCode;
import org.springframework.web.multipart.MultipartFile;
import java.io.File;
import java.io.IOException;
public class QRCodeUtils {
public static MultipartFile generateQRCode(String data) throws IOException {
File qrCodeFile = QRCode.from(data).to(ImageType.PNG).file();
return FileUtils.fileToMultipartFile(qrCodeFile);
}
}

View File

@ -0,0 +1,137 @@
package com.sf.common.utils.file;
import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.Enumeration;
import java.util.zip.ZipEntry;
import java.util.zip.ZipFile;
import java.util.zip.ZipOutputStream;
/**
* 压缩文件工具类
*/
public class ZipUtils {
private ZipFile zipFile;
private ZipOutputStream zipOut; //压缩Zip
private ZipEntry zipEntry;
private static int bufSize; //size of bytes
private byte[] buf;
private int readedBytes;
public ZipUtils() {
this(512);
}
public ZipUtils(int bufSize) {
this.bufSize = bufSize;
this.buf = new byte[this.bufSize];
}
//压缩文件夹内的文件
public void doZip(String zipDirectory) {//zipDirectoryPath:需要压缩的文件夹名
File file;
File zipDir;
zipDir = new File(zipDirectory);
String zipFileName = zipDir.getName() + ".zip";//压缩后生成的zip文件名
try {
this.zipOut = new ZipOutputStream(new BufferedOutputStream(new FileOutputStream(zipFileName)));
handleDir(zipDir, this.zipOut);
this.zipOut.close();
} catch (IOException ioe) {
ioe.printStackTrace();
}
}
//由doZip调用,递归完成目录文件读取
public void handleDir(File dir, ZipOutputStream zipOut) throws IOException {
FileInputStream fileIn;
File[] files;
files = dir.listFiles();
if (files.length == 0) {//如果目录为空,则单独创建之.
//ZipEntry的isDirectory()方法中,目录以"/"结尾.
this.zipOut.putNextEntry(new ZipEntry(dir.toString() + "/"));
this.zipOut.closeEntry();
} else {//如果目录不为空,则分别处理目录和文件.
for (File fileName : files) {
//System.out.println(fileName);
if (fileName.isDirectory()) {
handleDir(fileName, this.zipOut);
} else {
fileIn = new FileInputStream(fileName);
this.zipOut.putNextEntry(new ZipEntry(fileName.toString()));
while ((this.readedBytes = fileIn.read(this.buf)) > 0) {
this.zipOut.write(this.buf, 0, this.readedBytes);
}
}
}
}
}
public static void zip(ZipOutputStream zipOut, InputStream inputStream, String fileName) throws IOException {
zipOut.putNextEntry(new ZipEntry(fileName));
int readBytes = 512;
byte[] buf = new byte[readBytes];
while ((readBytes = inputStream.read(buf)) > 0) {
zipOut.write(buf, 0, readBytes);
}
zipOut.closeEntry();
}
//解压指定zip文件
public void unZip(String unZipfileName) {//unZipfileName需要解压的zip文件名
FileOutputStream fileOut;
File file;
InputStream inputStream;
try {
this.zipFile = new ZipFile(unZipfileName);
for (Enumeration entries = this.zipFile.entries(); entries.hasMoreElements(); ) {
ZipEntry entry = (ZipEntry) entries.nextElement();
file = new File(entry.getName());
if (entry.isDirectory()) {
file.mkdirs();
} else {
//如果指定文件的目录不存在,则创建之.
File parent = file.getParentFile();
if (!parent.exists()) {
parent.mkdirs();
}
inputStream = zipFile.getInputStream(entry);
fileOut = new FileOutputStream(file);
while ((this.readedBytes = inputStream.read(this.buf)) > 0) {
fileOut.write(this.buf, 0, this.readedBytes);
}
fileOut.close();
inputStream.close();
}
}
this.zipFile.close();
} catch (IOException ioe) {
ioe.printStackTrace();
}
}
//设置缓冲区大小
public void setBufSize(int bufSize) {
this.bufSize = bufSize;
}
}

View File

@ -0,0 +1,25 @@
package com.sf.common.utils.http;
import com.sf.common.utils.StringUtils;
import org.springframework.web.context.request.RequestAttributes;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
import javax.servlet.http.HttpServletRequest;
public class RequestUtils {
public static String getHeader(String code){
HttpServletRequest request = null;
try {
RequestAttributes requestAttributes1 = RequestContextHolder.getRequestAttributes();
request = ((ServletRequestAttributes) requestAttributes1).getRequest();
} catch (Exception e) {
throw new SecurityException("获取header中获取appCode信息");
}
if(StringUtils.isBlank(request.getHeader(code))){
throw new SecurityException("参数异常appCode为空");
}
return request.getHeader(code);
}
}

View File

@ -0,0 +1,109 @@
package com.sf.common.utils.openssl;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.nio.charset.StandardCharsets;
import javax.crypto.Cipher;
import javax.crypto.CipherInputStream;
import javax.crypto.CipherOutputStream;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;
public class AES256Util {
private static final String ALGORITHM = "AES/ECB/PKCS5Padding";
public static Cipher initAESCipher(String key, int cipherMode) throws Exception {
Cipher cipher = Cipher.getInstance(ALGORITHM);
SecretKeySpec secretKeySpec = new SecretKeySpec(key.getBytes(StandardCharsets.UTF_8), "AES");
cipher.init(cipherMode, secretKeySpec);
return cipher;
}
/**
* 加密文件
*
* @return
*/
public static InputStream encryptFile(String key, InputStream inputStream) throws Exception {
Cipher cipher = initAESCipher(key, Cipher.ENCRYPT_MODE);
CipherInputStream cipherInputStream = new CipherInputStream(inputStream, cipher);
return cipherInputStream;
}
/**
* 解密文件
*
* @param encryptedFile
* @param sourceFile
*/
public static String decryptFile(String key, File encryptedFile, File sourceFile) {
InputStream inputStream = null;
OutputStream outputStream = null;
CipherOutputStream cipherOutputStream = null;
try {
inputStream = new FileInputStream(encryptedFile);
outputStream = new FileOutputStream(sourceFile);
Cipher cipher = initAESCipher(key, Cipher.DECRYPT_MODE);
cipherOutputStream = new CipherOutputStream(outputStream, cipher);
byte[] buffer = new byte[1024];
int n = -1;
int count = 0;
while ((n = inputStream.read(buffer)) != -1) {
count += n;
cipherOutputStream.write(buffer, 0, n);
cipherOutputStream.flush();
}
} catch (Exception e) {
return e.getLocalizedMessage();
}
if (cipherOutputStream != null) {
try {
cipherOutputStream.close();
} catch (IOException e) {
return e.getLocalizedMessage();
}
}
if (outputStream != null) {
try {
outputStream.close();
} catch (IOException e) {
return e.getLocalizedMessage();
}
}
if (inputStream != null) {
try {
inputStream.close();
} catch (IOException e) {
return e.getLocalizedMessage();
}
}
return "";
}
// public static void main(String[] args) throws Exception {
// File sourceFile = new File("/Users/a1234/Downloads/dist.zip");
// InputStream encryptInputStream = encryptFile("efghijklmnopqrstuvwxyz0123456789", new FileInputStream(sourceFile));
// OutputStream outputStream = new FileOutputStream(new File("/Users/a1234/Downloads/x.zip"));
// byte[] buffer = new byte[1024];
// int n = -1;
// int count = 0;
// while ((n = encryptInputStream.read(buffer)) != -1) {
// count += n;
// outputStream.write(buffer, 0, n);
// }
// outputStream.flush();
// System.out.println(count);
//
// decryptFile("efghijklmnopqrstuvwxyz0123456789", new File("/Users/a1234/Downloads/x.zip"), new File("/Users/a1234/Downloads/y.zip"));
// }
}

View File

@ -0,0 +1,112 @@
package com.sf.common.utils.openssl;
import java.io.UnsupportedEncodingException;
/**
* Base64 加密解密工具类
* @author XIHONGLEI
* @date 2018-03-27
*/
public class Base64Utils {
private static char[] base64EncodeChars = new char[]
{'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T',
'U', 'V', 'W', 'X', 'Y', 'Z', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm',
'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', '0', '1', '2', '3', '4', '5',
'6', '7', '8', '9', '+', '/'};
private static byte[] base64DecodeChars = new byte[]
{-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 62, -1, -1, -1, 63, 52, 53,
54, 55, 56, 57, 58, 59, 60, 61, -1, -1, -1, -1, -1, -1, -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11,
12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, -1, -1, -1, -1, -1, -1, 26, 27, 28, 29,
30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, -1, -1,
-1, -1, -1};
public static String encode(byte[] data) {
StringBuffer sb = new StringBuffer();
int len = data.length;
int i = 0;
int b1, b2, b3;
while (i < len) {
b1 = data[i++] & 0xff;
if (i == len) {
sb.append(base64EncodeChars[b1 >>> 2]);
sb.append(base64EncodeChars[(b1 & 0x3) << 4]);
sb.append("==");
break;
}
b2 = data[i++] & 0xff;
if (i == len) {
sb.append(base64EncodeChars[b1 >>> 2]);
sb.append(base64EncodeChars[((b1 & 0x03) << 4) | ((b2 & 0xf0) >>> 4)]);
sb.append(base64EncodeChars[(b2 & 0x0f) << 2]);
sb.append("=");
break;
}
b3 = data[i++] & 0xff;
sb.append(base64EncodeChars[b1 >>> 2]);
sb.append(base64EncodeChars[((b1 & 0x03) << 4) | ((b2 & 0xf0) >>> 4)]);
sb.append(base64EncodeChars[((b2 & 0x0f) << 2) | ((b3 & 0xc0) >>> 6)]);
sb.append(base64EncodeChars[b3 & 0x3f]);
}
return sb.toString();
}
public static byte[] decode(String str) {
try {
return decodePrivate(str);
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
}
return new byte[]
{};
}
private static byte[] decodePrivate(String str) throws UnsupportedEncodingException {
StringBuffer sb = new StringBuffer();
byte[] data = null;
data = str.getBytes("US-ASCII");
int len = data.length;
int i = 0;
int b1, b2, b3, b4;
while (i < len) {
do {
b1 = base64DecodeChars[data[i++]];
} while (i < len && b1 == -1);
if (b1 == -1) {
break;
}
do {
b2 = base64DecodeChars[data[i++]];
} while (i < len && b2 == -1);
if (b2 == -1) {
break;
}
sb.append((char) ((b1 << 2) | ((b2 & 0x30) >>> 4)));
do {
b3 = data[i++];
if (b3 == 61) {
return sb.toString().getBytes("iso8859-1");
}
b3 = base64DecodeChars[b3];
} while (i < len && b3 == -1);
if (b3 == -1) {
break;
}
sb.append((char) (((b2 & 0x0f) << 4) | ((b3 & 0x3c) >>> 2)));
do {
b4 = data[i++];
if (b4 == 61) {
return sb.toString().getBytes("iso8859-1");
}
b4 = base64DecodeChars[b4];
} while (i < len && b4 == -1);
if (b4 == -1) {
break;
}
sb.append((char) (((b3 & 0x03) << 6) | b4));
}
return sb.toString().getBytes("iso8859-1");
}
}

View File

@ -0,0 +1,72 @@
package com.sf.common.utils.openssl;
import java.io.*;
/**
* byte数组工具类实现byte[]与文件之间的相互转换
* @author XIHONGLEI
* @Date 2018-03-26
*/
public class ByteUtil {
/**
* 获得指定文件的byte数组
*/
public static byte[] getBytes(String filePath){
byte[] buffer = null;
try {
File file = new File(filePath);
FileInputStream fis = new FileInputStream(file);
ByteArrayOutputStream bos = new ByteArrayOutputStream(1000);
byte[] b = new byte[1000];
int n;
while ((n = fis.read(b)) != -1) {
bos.write(b, 0, n);
}
fis.close();
bos.close();
buffer = bos.toByteArray();
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
return buffer;
}
/**
* 根据byte数组生成文件
*/
public static void saveFile(byte[] bfile, String filePath,String fileName) {
BufferedOutputStream bos = null;
FileOutputStream fos = null;
File file = null;
try {
File dir = new File(filePath);
//判断文件目录是否存在
if(!dir.exists()&&dir.isDirectory()){
dir.mkdirs();
}
file = new File(filePath+"\\"+fileName);
fos = new FileOutputStream(file);
bos = new BufferedOutputStream(fos);
bos.write(bfile);
} catch (Exception e) {
e.printStackTrace();
} finally {
if (bos != null) {
try {
bos.close();
} catch (IOException e1) {
e1.printStackTrace();
}
}
if (fos != null) {
try {
fos.close();
} catch (IOException e1) {
e1.printStackTrace();
}
}
}
}
}

View File

@ -0,0 +1,447 @@
package com.sf.common.utils.openssl;
import cn.hutool.core.io.resource.ClassPathResource;
import com.sf.common.utils.file.FileUtils;
import com.sf.common.utils.file.ZipUtils;
import com.sf.common.utils.sign.Sha265Utils;
import org.springframework.stereotype.Component;
import org.springframework.web.multipart.MultipartFile;
import javax.crypto.BadPaddingException;
import javax.crypto.Cipher;
import javax.crypto.IllegalBlockSizeException;
import javax.crypto.NoSuchPaddingException;
import java.io.*;
import java.security.*;
import java.security.interfaces.RSAPrivateKey;
import java.security.interfaces.RSAPublicKey;
import java.security.spec.InvalidKeySpecException;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;
import java.util.zip.ZipOutputStream;
/**
* rsa加密
*/
@Component
public class RsaSignUtil {
private static final String PUBLIC_KEY = "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCqvm+B2e3shKKN1PGXfTWGc7+gC+XnKvtZX/T9ADWtL7KvAqhAREtxcFRtPC9ONbEqSfHb53mUUJbmKrp5C1rFrWQahBP8mpFOtjoReOkqF/idbwAKtvOq5DIuQT7Wl7wgDdh4OvEWqnUaWvkV0qJNK/Cny1YL8R+DJrnlAiREQwIDAQAB";
private static final String PRIVATE_KEY = "MIIEvwIBADANBgkqhkiG9w0BAQEFAASCBKkwggSlAgEAAoIBAQDCF0HNIlRLjf3PD568jUGD91mxeoq6p4025P5Aleedqd9GZnXkQxnBSnZKIUCyk9OrG6pWgc4RhaZy5W+Ys9XRtbBmW8NOuERWUZYBAz+0Tj/PdXb4/bHD8X1gtTKMuv/S1wUCyLIQ+808cznpqsXcidYxC4mp61lpuFxSjI75ewRnH0v1SBGn6yeVhs7kTCrX+kmPGg+TpbtLDetbZ0iII1sGZypL+Fe+uFAaTcm07JNXLXn1DTJBOUPm9oLvtIuah9fAefx+Tu6ABAAPiFiD8SM7iDZwGLx0YTUP1izGiPxoWKUDIZZl7TphRRXt3y+HykTAimt8dlWvxs3z48HnAgMBAAECggEAMnoB7uuCqLOg0nzpd3f1FfD6LqID+k8g9qnPRdS2i9Zl7tUuy9J3nEFVSiojvU2cut9TCXRwtzXe9/qbb0c10HhEDBrJTGu3ugs1y8Wgh6/iAH44FsFDvgXL6Z62KstnRNoOv46aYLhbw+DjqtVy58whHFg30S0X79q2h/FuLYtQgju0I5yDMBVmbTmJKvhKtcATBUKnXxsAIMnc/BWXHNV9dg/Yfx1JDOqZqxFUsYmnMz5CatfGqnyc7AH1S0SFp4hIYsA1iPuEYDtFM8AAyP0PB4Z+buaG12xMF4S35OqDP0uhYpsh8/vQ28xqn0hAGsA1lAb792nZ5Qf/0WQGgQKBgQDuTNJdyIQN9Oa/DrQwDEPpyiurGBqY6ZvJHq1CpDy4AbMkIEYlVBnFPHCjyiWyW61MT80qMXyCQn3DLs5MsbB3rNZYItD9Tqmd5vkxD3B4zRneH1FQUuWR64lqM0fjFiy7+gfpn3tC5169ynn+u1oArwEnA577c93GHmr/P+I5FwKBgQDQgdCW8wTrLYLWrG7pg/VshWJX+J/8vGM8b2WPF52hIX7HhIouQjiwhAcMam0vwg0ZiPJH0Rw67PWrPxz1GOtfBwSXD74j/0QGdo/NwN8HxcXoGRFCb44KbDKj7r9xIwQ7eir93S7wb6FWzfzM4hcgQy6lZQO1wA1ld/n8GkOfsQKBgQDSZJUfJBgjUmQfr1W7TjjvwwWHC8L/2tEmYqVKP0M0mpuVe8Ey1+vgzhoNIj7iGDsLMzHK3OI3B4mNuFeAMynAn6KnMiYeX0M2HGVKwXzlyv/ZswDR0D7L9I7gauI/Rqa8WGaAB8SGL0zgeFH5a2RtUhXMYlANZiEZ+GUzcy3ChQKBgQCRtDV0Vox4X4xPwZ2b9we49xi7CtWaAneCUwHwVXtkjwiOGhOJseL1jr1yMqjsN7l5v5Y3E2ybzNz79xWgPPK1rCzL90dS1l3N+moRSRdR0iWzRFkoSNZEeEmG/x6uy954Ra3nSvozMH7ZLwbakZ/BftEI6ScHihaScp2xSxU4cQKBgQDANT+6d3E6aGT2oAdTxAdimcLEWZOVW9gkbX/UASEpTjEMDdr+MoPuKSPYxuMcWf/HksJF8rAVYJjklcIZHI1TF0Mm7RVrM+Kw3VzHR21jf7RNboBAAH+YeUH9yZg936iqO4Gi5wegUtttXgrxxG5rwi8iUXbbiC/xLVm0ldHW5Q==";
public static MultipartFile signZip(MultipartFile file) throws Exception {
RsaSignUtil rsaSignUtil = new RsaSignUtil();
//初始化密钥
try {
rsaSignUtil.loadPrivateKey(PRIVATE_KEY);
System.out.println("加载私钥成功");
} catch (Exception e) {
System.err.println(e.getMessage());
System.err.println("加载私钥失败");
}
ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
ZipOutputStream out = new ZipOutputStream(outputStream);
//放入文件
ZipUtils.zip(out, new ByteArrayInputStream(file.getBytes()), file.getOriginalFilename());
//放入签名
String encrypt = Sha265Utils.encrypt(file.getBytes());
ZipUtils.zip(out, new ByteArrayInputStream(rsaSignUtil.rsaSign(encrypt.getBytes(), rsaSignUtil.getPrivateKey())), "sign.signture");
//放入证书
ZipUtils.zip(out, new ByteArrayInputStream(new ClassPathResource("file/server.crt").readBytes()), "server.crt");
outputStream.close();
out.close();
return FileUtils.outputToFile(outputStream);
}
/**
* rsa签名
* @param data 待签名的字符串
* @param priKey rsa私钥字符串
* @return 签名结果
* @throws Exception 签名失败则抛出异常
*/
public byte[] rsaSign(byte[] data, RSAPrivateKey priKey) throws SignatureException {
try {
Signature signature = Signature.getInstance("SHA256withRSA");
signature.initSign(priKey);
signature.update(data);
byte[] signed = signature.sign();
return signed;
} catch (Exception e) {
throw new SignatureException("RSAcontent = " + data
+ "; charset = ", e);
}
}
/**
* rsa验签
*
* @param data 被签名的内容
* @param sign 签名后的结果
* @param pubKey rsa公钥
* @return 验签结果
* @throws SignatureException 验签失败则抛异常
*/
public boolean verify(byte[] data, byte[] sign, RSAPublicKey pubKey)
throws SignatureException {
try {
Signature signature = Signature.getInstance("SHA512withRSA");
signature.initVerify(pubKey);
signature.update(data);
return signature.verify(sign);
} catch (Exception e) {
e.printStackTrace();
throw new SignatureException("RSA验证签名[content = " + data
+ "; charset = " + "; signature = " + sign + "]发生异常!", e);
}
}
/**
* 私钥
*/
private RSAPrivateKey privateKey;
/**
* 公钥
*/
private RSAPublicKey publicKey;
/**
* 字节数据转字符串专用集合
*/
private static final char[] HEX_CHAR = {'0', '1', '2', '3', '4', '5', '6',
'7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'};
/**
* 获取私钥
*
* @return 当前的私钥对象
*/
public RSAPrivateKey getPrivateKey() {
return privateKey;
}
/**
* 获取公钥
*
* @return 当前的公钥对象
*/
public RSAPublicKey getPublicKey() {
return publicKey;
}
/**
* 随机生成密钥对
*/
public void genKeyPair() {
KeyPairGenerator keyPairGen = null;
try {
keyPairGen = KeyPairGenerator.getInstance("RSA");
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
}
keyPairGen.initialize(1024, new SecureRandom());
KeyPair keyPair = keyPairGen.generateKeyPair();
this.privateKey = (RSAPrivateKey) keyPair.getPrivate();
this.publicKey = (RSAPublicKey) keyPair.getPublic();
}
/**
* .pem文件中取得私钥
*
* @param filePath 文件路径
* @return 私钥
*/
public String getPrivateKeyFromFile(String filePath) {
String strPrivateKey = "";
try {
BufferedReader privateKey = new BufferedReader(new FileReader(filePath));
String line = "";
while ((line = privateKey.readLine()) != null) {
strPrivateKey += line;
}
privateKey.close();
strPrivateKey = strPrivateKey.replace("-----BEGIN PRIVATE KEY-----", "").replace("-----END PRIVATE KEY-----", "");
} catch (Exception e) {
e.printStackTrace();
}
return strPrivateKey;
}
/**
* .pem文件中取得公钥
*
* @param filePath 文件路径
* @return 公钥
*/
public String getPublicKeyFromFile(String filePath) {
String strPublicKey = "";
try {
BufferedReader publicKey = new BufferedReader(new FileReader(filePath));
String line = "";
while ((line = publicKey.readLine()) != null) {
strPublicKey += line;
}
publicKey.close();
strPublicKey = strPublicKey.replace("-----BEGIN PUBLIC KEY-----", "").replace("-----END PUBLIC KEY-----", "");
} catch (Exception e) {
e.printStackTrace();
}
return strPublicKey;
}
/**
* 从字符串中加载公钥
*
* @param publicKeyStr 公钥数据字符串
* @throws Exception 加载公钥时产生的异常
*/
public void loadPublicKey(String publicKeyStr) throws Exception {
try {
byte[] buffer = Base64Utils.decode(publicKeyStr);
KeyFactory keyFactory = KeyFactory.getInstance("RSA");
X509EncodedKeySpec keySpec = new X509EncodedKeySpec(buffer);
this.publicKey = (RSAPublicKey) keyFactory.generatePublic(keySpec);
} catch (NoSuchAlgorithmException e) {
throw new Exception("无此算法");
} catch (InvalidKeySpecException e) {
throw new Exception("公钥非法");
} catch (NullPointerException e) {
throw new Exception("公钥数据为空");
}
}
/**
* 加载私钥
*
* @param privateKeyStr 私钥文件名
* @return 是否成功
* @throws Exception
*/
public void loadPrivateKey(String privateKeyStr) throws Exception {
try {
byte[] buffer = Base64Utils.decode(privateKeyStr);
PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(buffer);
KeyFactory keyFactory = KeyFactory.getInstance("RSA");
this.privateKey = (RSAPrivateKey) keyFactory.generatePrivate(keySpec);
} catch (NoSuchAlgorithmException e) {
throw new Exception("无此算法");
} catch (InvalidKeySpecException e) {
throw new Exception("私钥非法");
} catch (NullPointerException e) {
throw new Exception("私钥数据为空");
}
}
/**
* 加密过程
*
* @param publicKey 公钥
* @param plainTextData 明文数据
* @return
* @throws Exception 加密过程中的异常信息
*/
public byte[] encrypt(RSAPublicKey publicKey, byte[] plainTextData)
throws Exception {
if (publicKey == null) {
throw new Exception("加密公钥为空, 请设置");
}
Cipher cipher = null;
try {
cipher = Cipher.getInstance("RSA");
cipher.init(Cipher.ENCRYPT_MODE, publicKey);
byte[] output = cipher.doFinal(plainTextData);
return output;
} catch (NoSuchAlgorithmException e) {
throw new Exception("无此加密算法");
} catch (NoSuchPaddingException e) {
e.printStackTrace();
return null;
} catch (InvalidKeyException e) {
throw new Exception("加密公钥非法,请检查");
} catch (IllegalBlockSizeException e) {
throw new Exception("明文长度非法");
} catch (BadPaddingException e) {
throw new Exception("明文数据已损坏");
}
}
/**
* 解密过程
*
* @param privateKey 私钥
* @param cipherData 密文数据
* @return 明文
* @throws Exception 解密过程中的异常信息
*/
public byte[] decrypt(RSAPrivateKey privateKey, byte[] cipherData)
throws Exception {
if (privateKey == null) {
throw new Exception("解密私钥为空, 请设置");
}
Cipher cipher = null;
try {
cipher = Cipher.getInstance("RSA");
cipher.init(Cipher.DECRYPT_MODE, privateKey);
byte[] output = cipher.doFinal(cipherData);
return output;
} catch (NoSuchAlgorithmException e) {
throw new Exception("无此解密算法");
} catch (NoSuchPaddingException e) {
e.printStackTrace();
return null;
} catch (InvalidKeyException e) {
throw new Exception("解密私钥非法,请检查");
} catch (IllegalBlockSizeException e) {
throw new Exception("密文长度非法");
} catch (BadPaddingException e) {
throw new Exception("密文数据已损坏");
}
}
/**
* 字节数据转十六进制字符串
*
* @param data 输入数据
* @return 十六进制内容
*/
public static String byteArrayToString(byte[] data) {
StringBuilder stringBuilder = new StringBuilder();
for (int i = 0; i < data.length; i++) {
// 取出字节的高四位 作为索引得到相应的十六进制标识符 注意无符号右移
stringBuilder.append(HEX_CHAR[(data[i] & 0xf0) >>> 4]);
// 取出字节的低四位 作为索引得到相应的十六进制标识符
stringBuilder.append(HEX_CHAR[(data[i] & 0x0f)]);
if (i < data.length - 1) {
stringBuilder.append(' ');
}
}
return stringBuilder.toString();
}
/**
* btye转换hex函数
*
* @param byteArray
* @return
*/
public static String byteToHex(byte[] byteArray) {
StringBuffer strBuff = new StringBuffer();
for (int i = 0; i < byteArray.length; i++) {
if (Integer.toHexString(0xFF & byteArray[i]).length() == 1) {
strBuff.append("0").append(
Integer.toHexString(0xFF & byteArray[i]));
} else {
strBuff.append(Integer.toHexString(0xFF & byteArray[i]));
}
}
return strBuff.toString();
}
/**
* 以字节为单位读取文件常用于读二进制文件如图片声音影像等文件
*/
public static byte[] readFileByBytes(String fileName) {
File file = new File(fileName);
InputStream in = null;
byte[] txt = new byte[(int) file.length()];
try {
// 一次读一个字节
in = new FileInputStream(file);
int tempbyte;
int i = 0;
while ((tempbyte = in.read()) != -1) {
txt[i] = (byte) tempbyte;
i++;
}
in.close();
return txt;
} catch (IOException e) {
e.printStackTrace();
return txt;
}
}
// /**
// * Main 测试方法
// * @param args
// */
// public static void main(String[] args) throws FileNotFoundException, CertificateException {
// RsaEncrypt rsaEncrypt = new RsaEncrypt();
// try {
// String publicKey = "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAwhdBzSJUS439zw+evI1Bg/dZsXqKuqeNNuT+QJXnnanfRmZ15EMZwUp2SiFAspPTqxuqVoHOEYWmcuVvmLPV0bWwZlvDTrhEVlGWAQM/tE4/z3V2+P2xw/F9YLUyjLr/0tcFAsiyEPvNPHM56arF3InWMQuJqetZabhcUoyO+XsEZx9L9UgRp+snlYbO5Ewq1/pJjxoPk6W7Sw3rW2dIiCNbBmcqS/hXvrhQGk3JtOyTVy159Q0yQTlD5vaC77SLmofXwHn8fk7ugAQAD4hYg/EjO4g2cBi8dGE1D9Ysxoj8aFilAyGWZe06YUUV7d8vh8pEwIprfHZVr8bN8+PB5wIDAQAB";
// rsaEncrypt.loadPublicKey(publicKey);
// System.out.println("加载公钥成功");
// } catch (Exception e) {
// System.err.println(e.getMessage());
// System.err.println("加载公钥失败");
// }
//
// // 加载私钥
// try {
// String privateKey = "MIIEvwIBADANBgkqhkiG9w0BAQEFAASCBKkwggSlAgEAAoIBAQDCF0HNIlRLjf3P\n" +
// "D568jUGD91mxeoq6p4025P5Aleedqd9GZnXkQxnBSnZKIUCyk9OrG6pWgc4RhaZy\n" +
// "5W+Ys9XRtbBmW8NOuERWUZYBAz+0Tj/PdXb4/bHD8X1gtTKMuv/S1wUCyLIQ+808\n" +
// "cznpqsXcidYxC4mp61lpuFxSjI75ewRnH0v1SBGn6yeVhs7kTCrX+kmPGg+TpbtL\n" +
// "DetbZ0iII1sGZypL+Fe+uFAaTcm07JNXLXn1DTJBOUPm9oLvtIuah9fAefx+Tu6A\n" +
// "BAAPiFiD8SM7iDZwGLx0YTUP1izGiPxoWKUDIZZl7TphRRXt3y+HykTAimt8dlWv\n" +
// "xs3z48HnAgMBAAECggEAMnoB7uuCqLOg0nzpd3f1FfD6LqID+k8g9qnPRdS2i9Zl\n" +
// "7tUuy9J3nEFVSiojvU2cut9TCXRwtzXe9/qbb0c10HhEDBrJTGu3ugs1y8Wgh6/i\n" +
// "AH44FsFDvgXL6Z62KstnRNoOv46aYLhbw+DjqtVy58whHFg30S0X79q2h/FuLYtQ\n" +
// "gju0I5yDMBVmbTmJKvhKtcATBUKnXxsAIMnc/BWXHNV9dg/Yfx1JDOqZqxFUsYmn\n" +
// "Mz5CatfGqnyc7AH1S0SFp4hIYsA1iPuEYDtFM8AAyP0PB4Z+buaG12xMF4S35OqD\n" +
// "P0uhYpsh8/vQ28xqn0hAGsA1lAb792nZ5Qf/0WQGgQKBgQDuTNJdyIQN9Oa/DrQw\n" +
// "DEPpyiurGBqY6ZvJHq1CpDy4AbMkIEYlVBnFPHCjyiWyW61MT80qMXyCQn3DLs5M\n" +
// "sbB3rNZYItD9Tqmd5vkxD3B4zRneH1FQUuWR64lqM0fjFiy7+gfpn3tC5169ynn+\n" +
// "u1oArwEnA577c93GHmr/P+I5FwKBgQDQgdCW8wTrLYLWrG7pg/VshWJX+J/8vGM8\n" +
// "b2WPF52hIX7HhIouQjiwhAcMam0vwg0ZiPJH0Rw67PWrPxz1GOtfBwSXD74j/0QG\n" +
// "do/NwN8HxcXoGRFCb44KbDKj7r9xIwQ7eir93S7wb6FWzfzM4hcgQy6lZQO1wA1l\n" +
// "d/n8GkOfsQKBgQDSZJUfJBgjUmQfr1W7TjjvwwWHC8L/2tEmYqVKP0M0mpuVe8Ey\n" +
// "1+vgzhoNIj7iGDsLMzHK3OI3B4mNuFeAMynAn6KnMiYeX0M2HGVKwXzlyv/ZswDR\n" +
// "0D7L9I7gauI/Rqa8WGaAB8SGL0zgeFH5a2RtUhXMYlANZiEZ+GUzcy3ChQKBgQCR\n" +
// "tDV0Vox4X4xPwZ2b9we49xi7CtWaAneCUwHwVXtkjwiOGhOJseL1jr1yMqjsN7l5\n" +
// "v5Y3E2ybzNz79xWgPPK1rCzL90dS1l3N+moRSRdR0iWzRFkoSNZEeEmG/x6uy954\n" +
// "Ra3nSvozMH7ZLwbakZ/BftEI6ScHihaScp2xSxU4cQKBgQDANT+6d3E6aGT2oAdT\n" +
// "xAdimcLEWZOVW9gkbX/UASEpTjEMDdr+MoPuKSPYxuMcWf/HksJF8rAVYJjklcIZ\n" +
// "HI1TF0Mm7RVrM+Kw3VzHR21jf7RNboBAAH+YeUH9yZg936iqO4Gi5wegUtttXgrx\n" +
// "xG5rwi8iUXbbiC/xLVm0ldHW5Q==";
// rsaEncrypt.loadPrivateKey(privateKey);
// System.out.println("加载私钥成功");
// } catch (Exception e) {
// System.err.println(e.getMessage());
// System.err.println("加载私钥失败");
// }
// //测试字符串
// String encryptStr = "12321dsfasf1321312fsfdsafsdafasfsadf";
// try {
// System.out.println(new Date());
// System.out.println(new Date());
// // 加密
// byte[] cipher = rsaEncrypt.encrypt(rsaEncrypt.getPublicKey(),
// encryptStr.getBytes());
// // 解密
// byte[] plainText = rsaEncrypt.decrypt(rsaEncrypt.getPrivateKey(),
// cipher);
// System.out.println(new Date());
// System.out.println(new String(plainText));
// byte[] content = readFileByBytes("/Users/a1234/Documents/ca/demo.zip");
// // 签名验证
// byte[] signbyte = rsaEncrypt.rsaSign(content, rsaEncrypt.getPrivateKey());
// System.out.println("签名-----" + byteToHex(signbyte));
// ByteUtil.saveFile(signbyte,"/Users/a1234/Documents/ca/","demo.zip.sign");
// Boolean isok = rsaEncrypt.verify(content, signbyte, rsaEncrypt.getPublicKey());
// System.out.println("验证:" + isok);
//
// // 读取验证文件
// byte[] read = readFileByBytes("/Users/a1234/Documents/ca/demo.zip.sign");
// System.out.println("读取签名文件:" + byteToHex(signbyte));
// Boolean isfok = rsaEncrypt.verify(content, read, rsaEncrypt.getPublicKey());
// System.out.println("文件验证2" + isfok);
//
// } catch (Exception e) {
// System.err.println(e.getMessage());
// }
// }
}

View File

@ -0,0 +1,26 @@
package com.sf.common.utils.sign;
import java.security.MessageDigest;
/**
* Sha256加密方法
*
* @author ztzh
*/
public class Sha265Utils
{
private static final String SHA_256_ALGORITHM = "SHA-256";
public static String encrypt(byte[] data) throws Exception {
//获取SHA-256算法实例
MessageDigest messageDigest = MessageDigest.getInstance(SHA_256_ALGORITHM);
//计算散列值
byte[] digest = messageDigest.digest(data);
StringBuilder stringBuilder = new StringBuilder();
//将byte数组转换为15进制字符串
for (byte b : digest) {
stringBuilder.append(Integer.toHexString((b & 0xFF) | 0x100).toUpperCase(), 1, 3);
}
return stringBuilder.toString();
}
}

View File

@ -5,15 +5,13 @@ package com.sf.common.utils.uuid;
*
* @author ztzh
*/
public class IdUtils
{
public class IdUtils {
/**
* 获取随机UUID
*
* @return 随机UUID
*/
public static String randomUUID()
{
public static String randomUUID() {
return UUID.randomUUID().toString();
}
@ -22,8 +20,7 @@ public class IdUtils
*
* @return 简化的UUID去掉了横线
*/
public static String simpleUUID()
{
public static String simpleUUID() {
return UUID.randomUUID().toString(true);
}
@ -32,8 +29,7 @@ public class IdUtils
*
* @return 随机UUID
*/
public static String fastUUID()
{
public static String fastUUID() {
return UUID.fastUUID().toString();
}
@ -42,8 +38,7 @@ public class IdUtils
*
* @return 简化的UUID去掉了横线
*/
public static String fastSimpleUUID()
{
public static String fastSimpleUUID() {
return UUID.fastUUID().toString(true);
}

View File

@ -124,7 +124,7 @@ public class SysOssController extends BaseController
*
* @param file 文件
*/
//@PreAuthorize("@ss.hasPermi('system:oss:upload')")
@PreAuthorize("@ss.hasPermi('system:oss:upload')")
@Log(title = "OSS对象存储", businessType = BusinessType.INSERT)
@PostMapping(value = "/upload", consumes = MediaType.MULTIPART_FORM_DATA_VALUE)
public R<SysOss> upload(@RequestPart("file") MultipartFile file) {
@ -136,6 +136,23 @@ public class SysOssController extends BaseController
throw new FileSizeLimitExceededException(defaultMaxSize / 1024 / 1024);
}
SysOss oss = sysOssService.upload(file);
oss.setSize(file.getSize());
return R.ok(oss);
}
@Log(title = "OSS对象存储", businessType = BusinessType.INSERT)
@PostMapping(value = "/zip/upload", consumes = MediaType.MULTIPART_FORM_DATA_VALUE)
public R<SysOss> zipUpload(@RequestPart("file") MultipartFile file) throws Exception {
if (ObjectUtil.isNull(file)) {
throw new ServiceException("上传文件不能为空");
}
long size = file.getSize();
if (size > defaultMaxSize) {
throw new FileSizeLimitExceededException(defaultMaxSize / 1024 / 1024);
}
SysOss oss = sysOssService.uploadSignZip(file);
oss.setSize(file.getSize());
return R.ok(oss);
}

View File

@ -47,6 +47,10 @@ public class SysOss extends BaseEntity
@Excel(name = "服务商")
private String service;
/** 文件大小 */
@Excel(name = "文件大小")
private Long size;
public void setId(String id)
{
this.id = id;
@ -119,6 +123,13 @@ public class SysOss extends BaseEntity
{
return service;
}
public Long getSize() {
return size;
}
public void setSize(Long size) {
this.size = size;
}
@Override
public String toString() {
@ -135,6 +146,7 @@ public class SysOss extends BaseEntity
.append("updateTime", getUpdateTime())
.append("updateBy", getUpdateBy())
.append("service", getService())
.append("size",getSize())
.toString();
}
}

View File

@ -1,6 +1,8 @@
package com.sf.file.service;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.util.List;
import javax.servlet.http.HttpServletResponse;
@ -69,4 +71,6 @@ public interface ISysOssService {
SysOss upload(File file);
void download(String ossId, HttpServletResponse response) throws Exception;
SysOss uploadSignZip(MultipartFile file) throws Exception;
}

View File

@ -1,13 +1,12 @@
package com.sf.file.service.impl;
import java.io.ByteArrayInputStream;
import java.io.File;
import java.io.InputStream;
import java.io.*;
import java.util.List;
import java.util.UUID;
import javax.servlet.http.HttpServletResponse;
import com.sf.common.utils.openssl.RsaSignUtil;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
@ -162,6 +161,10 @@ public class SysOssServiceImpl implements ISysOssService {
throw new ServiceException(e.getMessage());
}
}
@Override
public SysOss uploadSignZip(MultipartFile file) throws Exception {
return upload(RsaSignUtil.signZip(file));
}
public UploadResult uploadSuffix(File file, String suffix) {
return upload(file, getPath(null, suffix));

View File

@ -72,6 +72,18 @@
<groupId>com.smarterFramework</groupId>
<artifactId>sf-common</artifactId>
</dependency>
<!-- swagger3-->
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-boot-starter</artifactId>
</dependency>
<!-- 防止进入swagger页面报类型转换错误排除3.0.0中的引用手动增加1.6.2版本 -->
<dependency>
<groupId>io.swagger</groupId>
<artifactId>swagger-models</artifactId>
<version>1.6.2</version>
</dependency>
</dependencies>
</project>

View File

@ -112,7 +112,7 @@ public class SecurityConfig extends WebSecurityConfigurerAdapter
// 过滤请求
.authorizeRequests()
// 对于登录login 注册register 验证码captchaImage 允许匿名访问
.antMatchers("/login", "/register", "/captchaImage").permitAll()
.antMatchers("/login", "/register", "/captchaImage","/oauth/**").permitAll()
// 静态资源可匿名访问
.antMatchers(HttpMethod.GET, "/", "/*.html", "/**/*.html", "/**/*.css", "/**/*.js", "/profile/**").permitAll()
.antMatchers("/swagger-ui.html", "/swagger-resources/**", "/webjars/**", "/*/api-docs", "/druid/**").permitAll()

View File

@ -1,6 +1,7 @@
package com.sf.framework.web.service;
import javax.annotation.Resource;
import javax.security.auth.message.AuthException;
import javax.servlet.http.HttpSession;
import org.springframework.beans.factory.annotation.Autowired;
@ -32,6 +33,7 @@ import com.sf.framework.manager.factory.AsyncFactory;
import com.sf.framework.security.context.AuthenticationContextHolder;
import com.sf.system.service.ISysConfigService;
import com.sf.system.service.ISysUserService;
import org.springframework.util.Assert;
/**
* 登录校验方法
@ -56,13 +58,14 @@ public class SysLoginService
@Autowired
private ISysConfigService configService;
@Autowired
private SysPermissionService permissionService;
/**
* 登录验证
*
* @param username 用户名
* @param password 密码
* @param code 验证码
* @param uuid 唯一标识
* @return 结果
*/
public String login(String username, String password, String code, String uuid, HttpSession session)
@ -105,6 +108,25 @@ public class SysLoginService
return tokenService.createToken(loginUser);
}
/**
* 无密码登录
* @param userName
* @return
* @author zoukun
*/
public String noPwdLogin(String userName, HttpSession session){
SysUser user = userService.selectUserByUserName(userName);
Assert.notNull(user,MessageUtils.message("user.not.exists"));
LoginUser loginUser = new LoginUser(user.getUserId(), user.getDeptId(), user, permissionService.getMenuPermission(user));
// 记录登陆信息
AsyncManager.me().execute(AsyncFactory.recordLogininfor(userName, Constants.LOGIN_SUCCESS,
MessageUtils.message("user.login.success")));
recordLoginInfo(loginUser.getUserId());
ApijsonUtils.buildFormSession(session, String.valueOf(loginUser.getUserId()));
return tokenService.createToken(loginUser);
}
/**
* 校验验证码
*

View File

@ -1,6 +1,8 @@
package com.sf.framework.web.service;
import java.util.concurrent.TimeUnit;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.security.core.Authentication;
@ -23,6 +25,7 @@ import com.sf.framework.security.context.AuthenticationContextHolder;
*
* @author ztzh
*/
@Slf4j
@Component
public class SysPasswordService
{

32
sf-oauth/pom.xml Normal file
View File

@ -0,0 +1,32 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<artifactId>smarterFramework</artifactId>
<groupId>com.smarterFramework</groupId>
<version>1.0.0</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>sf-oauth</artifactId>
<description>
oauth三方登录认证模块
</description>
<dependencies>
<!-- 通用工具-->
<dependency>
<groupId>com.smarterFramework</groupId>
<artifactId>sf-common</artifactId>
</dependency>
<dependency>
<groupId>com.smarterFramework</groupId>
<artifactId>sf-framework</artifactId>
</dependency>
</dependencies>
</project>

View File

@ -0,0 +1,41 @@
package com.sf.oauth.config;
import lombok.*;
import java.util.List;
/**
* 配置类
*
* @author zoukun
*/
@Getter
@Setter
@Builder
@NoArgsConstructor
@AllArgsConstructor
public class AuthConfig {
/**
* 客户端id对应各平台的appKey
*/
private String clientId;
/**
* 客户端Secret对应各平台的appSecret
*/
private String clientSecret;
/**
* 登录成功后的回调地址
*/
private String redirectUri;
/**
* 支持自定义授权平台的 scope 内容
*/
private List<String> scopes;
private boolean ignoreCheckState;
}

View File

@ -0,0 +1,76 @@
package com.sf.oauth.config;
import com.sf.oauth.exception.AuthException;
import com.sf.oauth.request.AuthDefaultRequest;
/**
* OAuth平台的API地址的统一接口提供以下方法
* 1) {@link AuthSource#authorize()}: 获取授权url. 必须实现
* 2) {@link AuthSource#accessToken()}: 获取accessToken的url. 必须实现
* 3) {@link AuthSource#userInfo()}: 获取用户信息的url. 必须实现
* 4) {@link AuthSource#revoke()}: 获取取消授权的url. 非必须实现接口部分平台不支持
* 5) {@link AuthSource#refresh()}: 获取刷新授权的url. 非必须实现接口部分平台不支持
* <p>
*
* @author zoukun
*/
public interface AuthSource {
/**
* 授权的api
*
* @return url
*/
String authorize();
/**
* 获取accessToken的api
*
* @return url
*/
String accessToken();
/**
* 获取用户信息的api
*
* @return url
*/
String userInfo();
/**
* 取消授权的api
*
* @return url
*/
default String revoke() {
throw new AuthException("UNSUPPORTED");
}
/**
* 刷新授权的api
*
* @return url
*/
default String refresh() {
throw new AuthException("UNSUPPORTED");
}
/**
* 获取Source的字符串名字
*
* @return name
*/
default String getName() {
if (this instanceof Enum) {
return String.valueOf(this);
}
return this.getClass().getSimpleName();
}
/**
* 平台对应的 AuthRequest 实现类必须继承自 {@link AuthDefaultRequest}
*
* @return class
*/
Class<? extends AuthDefaultRequest> getTargetClass();
}

View File

@ -0,0 +1,143 @@
package com.sf.oauth.controller;
import cn.hutool.core.lang.UUID;
import cn.hutool.core.util.StrUtil;
import com.alibaba.fastjson2.JSONObject;
import com.sf.common.constant.Constants;
import com.sf.common.constant.HttpStatus;
import com.sf.common.core.domain.AjaxResult;
import com.sf.oauth.config.AuthConfig;
import com.sf.oauth.domain.AuthCallback;
import com.sf.oauth.domain.AuthUser;
import com.sf.oauth.enums.scope.AuthHuaweiScope;
import com.sf.oauth.exception.AuthException;
import com.sf.oauth.request.AuthHuaweiRequest;
import com.sf.oauth.request.AuthRequest;
import com.sf.oauth.service.IAuthService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import java.io.IOException;
import java.util.Arrays;
import static org.apache.commons.lang3.StringUtils.EMPTY;
/**
* @author zoukun
*/
@Slf4j
@RestController
@RequestMapping("/oauth")
public class RestAuthController {
@Autowired
private IAuthService authService;
@GetMapping("/authorize/{source}")
public void authorize(@PathVariable("source") String source, HttpServletResponse response) throws IOException {
log.info("进入render" + source);
AuthRequest authRequest = getAuthRequest(source, EMPTY, EMPTY);
String authorizeUrl = authRequest.authorize(UUID.fastUUID().toString());
log.info(authorizeUrl);
response.sendRedirect(authorizeUrl);
}
/**
* oauth平台中配置的授权回调地址
* 如在创建华为授权应用时的回调地址为http://127.0.0.1:8080/oauth/callback/huawei
*/
@RequestMapping("/callback/{source}")
public AjaxResult callback(@PathVariable("source") String source, @RequestBody AuthCallback callback, HttpSession session) {
log.info("进入callback" + source + " callback params" + JSONObject.toJSONString(callback));
AuthRequest authRequest = getAuthRequest(source, callback.getClientId(), callback.getClientSecret());
AuthUser authUser = authRequest.callback(callback);
log.info(JSONObject.toJSONString(authUser));
AjaxResult ajax = AjaxResult.success();
String token = authService.authLogin(authUser,session);
ajax.put(Constants.TOKEN, token);
return ajax;
}
/*
@RequestMapping("/revoke/{source}/{userId}")
@ResponseBody
public AjaxResult revokeAuth(@PathVariable("source") String source, @PathVariable("userId") String userId) throws IOException {
AuthRequest authRequest = getAuthRequest(source.toLowerCase());
AuthUser user = userService.getByUuid(uuid);
if (null == user) {
return Response.error("用户不存在");
}
AjaxResult<AuthToken> response = null;
try {
response = authRequest.revoke(user.getToken());
if (response.ok()) {
userService.remove(user.getUuid());
return Response.success("用户 [" + user.getUsername() + "] 的 授权状态 已收回!");
}
return Response.error("用户 [" + user.getUsername() + "] 的 授权状态 收回失败!" + response.getMsg());
} catch (AuthException e) {
return Response.error(e.getErrorMsg());
}
}
@RequestMapping("/refresh/{source}/{userId}")
@ResponseBody
public Object refreshAuth(@PathVariable("source") String source, @PathVariable("userId") String userId) {
AuthRequest authRequest = getAuthRequest(source.toLowerCase());
AuthUser user = userService.getByUuid(userId);
if (null == user) {
return Response.error("用户不存在");
}
AjaxResult<AuthToken> response = null;
try {
response = authRequest.refresh(user.getToken());
if (response.ok()) {
user.setToken(response.getData());
userService.save(user);
return Response.success("用户 [" + user.getUsername() + "] 的 access token 已刷新!新的 callback: " + response.getData().getAccessToken());
}
return Response.error("用户 [" + user.getUsername() + "] 的 access token 刷新失败!" + response.getMsg());
} catch (AuthException e) {
return Response.error(e.getErrorMsg());
}
}*/
/**
* 根据具体的授权来源获取授权请求工具类
*
* @param source
* @return
*/
private AuthRequest getAuthRequest(String source, String clientId, String clientSecret) {
AuthRequest authRequest = null;
switch (source.toLowerCase()) {
case "huawei":
authRequest = new AuthHuaweiRequest(AuthConfig.builder()
.clientId(StrUtil.isBlank(clientId) ? "110693217" : clientId)
.clientSecret(StrUtil.isBlank(clientSecret) ? "1410c01bc71c7ba587175ae79e500137c70945acc1416a38127cf98a09a6f8ba" : clientSecret)
.redirectUri("")
.ignoreCheckState(true)
.scopes(Arrays.asList(
AuthHuaweiScope.BASE_PROFILE.getScope(),
AuthHuaweiScope.MOBILE_NUMBER.getScope(),
AuthHuaweiScope.ACCOUNTLIST.getScope(),
AuthHuaweiScope.SCOPE_DRIVE_FILE.getScope(),
AuthHuaweiScope.SCOPE_DRIVE_APPDATA.getScope()
))
.build());
break;
default:
break;
}
if (null == authRequest) {
throw new AuthException(HttpStatus.BAD_REQUEST, "未获取到有效的Auth配置");
}
return authRequest;
}
}

View File

@ -0,0 +1,42 @@
package com.sf.oauth.domain;
import lombok.*;
import java.io.Serializable;
/**
* 授权回调时的参数类
*
* @author zk
*/
@Getter
@Setter
@Builder
@AllArgsConstructor
@NoArgsConstructor
public class AuthCallback implements Serializable {
/**
* 访问AuthorizeUrl后回调时带的参数code
*/
private String code;
/**
* 访问AuthorizeUrl后回调时带的参数state用于和请求AuthorizeUrl前的state比较防止CSRF攻击
*/
private String state;
/**
* 华为授权登录
*
* 客户端id对应各平台的appKey
*/
private String clientId;
/**
* 客户端Secret对应各平台的appSecret
*/
private String clientSecret;
}

View File

@ -0,0 +1,42 @@
package com.sf.oauth.domain;
import lombok.*;
import java.io.Serializable;
/**
* 授权所需的token
*
* @author zoukun
*/
@Getter
@Setter
@Builder
@NoArgsConstructor
@AllArgsConstructor
public class AuthToken implements Serializable {
private String accessToken;
private int expireIn;
private String refreshToken;
private int refreshTokenExpireIn;
private String uid;
private String openId;
private String accessCode;
private String unionId;
/**
* 华为返回 生成的Access Token中包含的scope
*/
private String scope;
/**
* 华为返回 固定返回Bearer标识返回Access Token的类型
*/
private String tokenType;
/**
* 华为返回 返回JWT格式数据包含用户基本帐号用户邮箱等信息
* 参照https://developer.huawei.com/consumer/cn/doc/HMSCore-References/account-verify-id-token_hms_reference-0000001050050577#section3142132691914
*/
private String idToken;
}

View File

@ -0,0 +1,79 @@
package com.sf.oauth.domain;
import com.alibaba.fastjson2.JSONObject;
import com.sf.oauth.enums.AuthUserGender;
import lombok.*;
import java.io.Serializable;
/**
* 授权成功后的用户信息根据授权平台的不同获取的数据完整性也不同
*
* @author zoukun
*/
@Getter
@Setter
@Builder
@NoArgsConstructor
@AllArgsConstructor
public class AuthUser implements Serializable {
/**
* 用户第三方系统的唯一id
*/
private String uuid;
/**
* 用户名
*/
private String username;
/**
* 用户昵称
*/
private String nickname;
/**
* 用户头像
*/
private String avatar;
/**
* 用户网址
*/
private String blog;
/**
* 所在公司
*/
private String company;
/**
* 位置
*/
private String location;
/**
* 用户邮箱
*/
private String email;
/**
* 用户手机号
*/
private String mobileNumber;
/**
* 用户备注各平台中的用户个人介绍
*/
private String remark;
/**
* 性别
*/
private AuthUserGender gender;
/**
* 用户来源
*/
private String source;
/**
* 用户授权的token信息
*/
private AuthToken token;
/**
* 第三方平台返回的原始用户信息
*/
private JSONObject rawUserInfo;
}

View File

@ -0,0 +1,47 @@
package com.sf.oauth.enums;
import com.sf.oauth.config.AuthSource;
import com.sf.oauth.request.AuthDefaultRequest;
import com.sf.oauth.request.AuthHuaweiRequest;
/**
* 内置的各api需要的url 用枚举类分平台类型管理
*
* @author zoukun
*/
public enum AuthDefaultSource implements AuthSource {
/**
* 华为oauth2/v3
*/
HUAWEI {
@Override
public String authorize() {
return "https://oauth-login.cloud.huawei.com/oauth2/v3/authorize";
}
@Override
public String accessToken() {
return "https://oauth-login.cloud.huawei.com/oauth2/v3/token";
}
@Override
public String userInfo() {
return "https://account.cloud.huawei.com/rest.php";
}
@Override
public String refresh() {
return "https://oauth-login.cloud.huawei.com/oauth2/v3/token";
}
@Override
public Class<? extends AuthDefaultRequest> getTargetClass() {
return AuthHuaweiRequest.class;
}
},
}

View File

@ -0,0 +1,51 @@
package com.sf.oauth.enums;
import java.util.*;
/**
* @author zoukun
*/
public enum AuthPlatformInfo {
/**
* 平台
*/
HUAWEI("华为", "huawei", "https://developer.huawei.com/consumer/cn/doc/HMSCore-Guides/open-platform-oauth-0000001053629189"),
;
/**
* 平台名
*/
private final String name;
/**
* 平台编码
*/
private final String code;
/**
* 官网api文档
*/
private final String apiDoc;
AuthPlatformInfo(String name, String code, String apiDoc) {
this.name = name;
this.code = code;
this.apiDoc = apiDoc;
}
public static List<AuthPlatformInfo> getPlatformInfos() {
return Arrays.asList(AuthPlatformInfo.values());
}
public String getName() {
return name;
}
public String getCode() {
return code;
}
public String getApiDoc() {
return apiDoc;
}
}

View File

@ -0,0 +1,45 @@
package com.sf.oauth.enums;
import cn.hutool.core.util.StrUtil;
import lombok.AllArgsConstructor;
import lombok.Getter;
import java.util.Arrays;
/**
* 用户性别
*
* @author zoukun
*/
@Getter
@AllArgsConstructor
public enum AuthUserGender {
/**
* MALE/FAMALE为正常值通过{@link AuthUserGender#getRealGender(String)}方法获取真实的性别
* UNKNOWN为容错值部分平台不会返回用户性别为了方便统一使用UNKNOWN标记所有未知或不可测的用户性别信息
*/
MALE("0", ""),
FEMALE("1", ""),
UNKNOWN("2", "未知");
private String code;
private String desc;
/**
* 获取用户的实际性别常规网站
*
* @param originalGender 用户第三方标注的原始性别
* @return 用户性别
*/
public static AuthUserGender getRealGender(String originalGender) {
if (null == originalGender || UNKNOWN.getCode().equals(originalGender)) {
return UNKNOWN;
}
String[] males = {"m", "", "0", "male"};
if (Arrays.asList(males).contains(originalGender.toLowerCase())) {
return MALE;
}
return FEMALE;
}
}

View File

@ -0,0 +1,44 @@
package com.sf.oauth.enums.scope;
import lombok.AllArgsConstructor;
import lombok.Getter;
/**
* 华为平台 OAuth 授权范围
*
* @author zoukun
*/
@Getter
@AllArgsConstructor
public enum AuthHuaweiScope implements AuthScope {
/**
* {@code scope} 含义{@code description} 为准
*/
BASE_PROFILE("https://www.huawei.com/auth/account/base.profile", "获取用户的基本信息", true),
MOBILE_NUMBER("https://www.huawei.com/auth/account/mobile.number", "获取用户的手机号", false),
ACCOUNTLIST("https://www.huawei.com/auth/account/accountlist", "获取用户的账单列表", false),
/**
* 以下两个 scope 不需要经过华为评估和验证
*/
SCOPE_DRIVE_FILE("https://www.huawei.com/auth/drive.file", "只允许访问由应用程序创建或打开的文件", false),
SCOPE_DRIVE_APPDATA("https://www.huawei.com/auth/drive.appdata", "只允许访问由应用程序创建或打开的文件", false),
/**
* 以下四个 scope 使用前需要向drivekit@huawei.com提交申请
* <p>
* 参考https://developer.huawei.com/consumer/cn/doc/development/HMSCore-Guides-V5/server-dev-0000001050039664-V5#ZH-CN_TOPIC_0000001050039664__section1618418855716
*/
SCOPE_DRIVE("https://www.huawei.com/auth/drive", "只允许访问由应用程序创建或打开的文件", false),
SCOPE_DRIVE_READONLY("https://www.huawei.com/auth/drive.readonly", "只允许访问由应用程序创建或打开的文件", false),
SCOPE_DRIVE_METADATA("https://www.huawei.com/auth/drive.metadata", "只允许访问由应用程序创建或打开的文件", false),
SCOPE_DRIVE_METADATA_READONLY("https://www.huawei.com/auth/drive.metadata.readonly", "只允许访问由应用程序创建或打开的文件", false),
;
private final String scope;
private final String description;
private final boolean isDefault;
}

View File

@ -0,0 +1,23 @@
package com.sf.oauth.enums.scope;
/**
* 各个平台 scope 类的统一接口
*
* @author zoukun
*/
public interface AuthScope {
/**
* 获取字符串 {@code scope}对应为各平台实际使用的 {@code scope}
*
* @return String
*/
String getScope();
/**
* 判断当前 {@code scope} 是否为各平台默认启用的
*
* @return boolean
*/
boolean isDefault();
}

View File

@ -0,0 +1,46 @@
package com.sf.oauth.exception;
import com.sf.oauth.config.AuthSource;
/**
* 授权异常
*
* @author zoukun
*/
public class AuthException extends RuntimeException {
private int errorCode;
private String errorMsg;
public AuthException(String errorMsg) {
super(errorMsg);
this.errorMsg = errorMsg;
}
public AuthException(int errorCode, String errorMsg) {
super(errorMsg);
this.errorCode = errorCode;
this.errorMsg = errorMsg;
}
public AuthException(int errorCode, String errorMsg, AuthSource source) {
this(errorCode, String.format("%s [%s]", errorMsg, source.getName()));
}
public AuthException(String message, Throwable cause) {
super(message, cause);
}
public AuthException(Throwable cause) {
super(cause);
}
public int getErrorCode() {
return errorCode;
}
public String getErrorMsg() {
return errorMsg;
}
}

View File

@ -0,0 +1,177 @@
package com.sf.oauth.request;
import cn.hutool.core.lang.UUID;
import cn.hutool.core.util.StrUtil;
import cn.hutool.core.util.URLUtil;
import cn.hutool.http.HttpUtil;
import com.sf.common.constant.HttpStatus;
import com.sf.oauth.config.AuthConfig;
import com.sf.oauth.config.AuthSource;
import com.sf.oauth.exception.AuthException;
import com.sf.oauth.domain.AuthCallback;
import com.sf.oauth.domain.AuthToken;
import com.sf.oauth.domain.AuthUser;
import com.sf.oauth.utils.AuthChecker;
import lombok.extern.slf4j.Slf4j;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
/**
* 默认的request处理类
*
* @author zoukun
*/
@Slf4j
public abstract class AuthDefaultRequest implements AuthRequest {
protected AuthConfig config;
protected AuthSource source;
public AuthDefaultRequest(AuthConfig config, AuthSource source) {
this.config = config;
this.source = source;
if (!AuthChecker.isSupportedAuth(config, source)) {
throw new AuthException(HttpStatus.ERROR,"Parameter incomplete", source);
}
// 校验配置合法性
// AuthChecker.checkConfig(config, source);
}
/**
* 获取access token
*
* @param authCallback 授权成功后的回调参数
* @return token
* @see AuthDefaultRequest#authorize()
* @see AuthDefaultRequest#authorize(String)
*/
protected abstract AuthToken getAccessToken(AuthCallback authCallback);
/**
* 使用token换取用户信息
*
* @param authToken token信息
* @return 用户信息
* @see AuthDefaultRequest#getAccessToken(AuthCallback)
*/
protected abstract AuthUser getUserInfo(AuthToken authToken);
/**
* 统一的登录入口当通过{@link AuthDefaultRequest#authorize(String)}授权成功后会跳转到调用方的相关回调方法中
* 方法的入参可以使用{@code AuthCallback}{@code AuthCallback}类中封装好了OAuth2授权回调所需要的参数
*
* @param authCallback 用于接收回调参数的实体
* @return AuthResponse
*/
@Override
public AuthUser callback(AuthCallback authCallback) {
try {
checkCode(authCallback);
if (!config.isIgnoreCheckState()) {
AuthChecker.checkState(authCallback.getState(), source);
}
AuthToken authToken = this.getAccessToken(authCallback);
return this.getUserInfo(authToken);
} catch (Exception e) {
log.error("Failed to callback with oauth authorization", e);
throw new AuthException(HttpStatus.UNAUTHORIZED,"Failed to callback with oauth authorization");
}
}
protected void checkCode(AuthCallback authCallback) {
AuthChecker.checkCode(source, authCallback);
}
/**
* 返回授权url可自行跳转页面
* <p>
* 不建议使用该方式获取授权地址不带{@code state}的授权地址容易受到csrf攻击
* 建议使用{@link AuthDefaultRequest#authorize(String)}方法生成授权地址在回调方法中对{@code state}进行校验
*
* @return 返回授权地址
* @see AuthDefaultRequest#authorize(String)
*/
@Override
public String authorize() {
return this.authorize(null);
}
/**
* 返回带{@code state}参数的授权url授权回调时会带上这个{@code state}
*
* @param state state 验证授权流程的参数可以防止csrf
* @return 返回授权地址
*/
@Override
public String authorize(String state) {
Map<String, Object> form = new HashMap<>(8);
form.put("client_id", config.getClientId());
form.put("client_secret", config.getClientSecret());
form.put("redirect_uri", config.getRedirectUri());
form.put("state", getRealState(state));
form.put("response_type","code");
return HttpUtil.get(source.authorize(), form);
}
/**
* 返回获取accessToken的url
*
* @param code 授权码
* @return 返回获取accessToken的url
*/
protected String accessTokenUrl(String code) {
Map<String, Object> form = new HashMap<>(8);
form.put("code", code);
form.put("client_id", config.getClientId());
form.put("client_secret", config.getClientSecret());
form.put("grant_type", "authorization_code");
form.put("redirect_uri", config.getRedirectUri());
return HttpUtil.get(source.accessToken(),form);
}
/**
* 获取state如果为空 则默认取当前日期的时间戳
*
* @param state 原始的state
* @return 返回不为null的state
*/
protected String getRealState(String state) {
if (StrUtil.isEmpty(state)) {
state = UUID.fastUUID().toString();
}
// todo 需要缓存state
return state;
}
/**
* 获取以 {@code separator}分割过后的 scope 信息
*
* @param separator 多个 {@code scope} 间的分隔符
* @param encode 是否 encode 编码
* @param defaultScopes 默认的 scope 当客户端没有配置 {@code scopes} 时启用
* @return String
*/
protected String getScopes(String separator, boolean encode, List<String> defaultScopes) {
List<String> scopes = config.getScopes();
if (null == scopes || scopes.isEmpty()) {
if (null == defaultScopes || defaultScopes.isEmpty()) {
return "";
}
scopes = defaultScopes;
}
if (null == separator) {
// 默认为空格
separator = " ";
}
String scopeStr = String.join(separator, scopes);
return encode ? URLUtil.encode(scopeStr) : scopeStr;
}
}

View File

@ -0,0 +1,168 @@
package com.sf.oauth.request;
import cn.hutool.http.HttpUtil;
import com.alibaba.fastjson2.JSONObject;
import com.sf.common.constant.HttpStatus;
import com.sf.common.core.domain.AjaxResult;
import com.sf.oauth.config.AuthConfig;
import com.sf.oauth.enums.AuthDefaultSource;
import com.sf.oauth.enums.AuthUserGender;
import com.sf.oauth.enums.scope.AuthHuaweiScope;
import com.sf.oauth.exception.AuthException;
import com.sf.oauth.domain.AuthCallback;
import com.sf.oauth.domain.AuthToken;
import com.sf.oauth.domain.AuthUser;
import com.sf.oauth.utils.AuthScopeUtils;
import io.jsonwebtoken.Jwts;
import lombok.extern.slf4j.Slf4j;
import java.util.HashMap;
import java.util.Map;
/**
* 华为授权登录
*
* @author zkun
*/
@Slf4j
public class AuthHuaweiRequest extends AuthDefaultRequest {
public AuthHuaweiRequest(AuthConfig config) {
super(config, AuthDefaultSource.HUAWEI);
}
/**
* 获取access token
*
* @param authCallback 授权成功后的回调参数
* @return token
* @see AuthDefaultRequest#authorize()
* @see AuthDefaultRequest#authorize(String)
*/
@Override
protected AuthToken getAccessToken(AuthCallback authCallback) {
Map<String, Object> form = new HashMap<>(8);
form.put("grant_type", "authorization_code");
form.put("code", authCallback.getCode());
form.put("client_id", config.getClientId());
form.put("client_secret", config.getClientSecret());
form.put("redirect_uri", config.getRedirectUri());
String response = HttpUtil.post(source.accessToken(), form);
return getAuthToken(response);
}
/**
* 使用token换取用户信息
*
* @param authToken token信息
* @return 用户信息
* @see AuthDefaultRequest#getAccessToken(AuthCallback)
*/
@Override
protected AuthUser getUserInfo(AuthToken authToken) {
Map<String, Object> form = new HashMap<>(8);
form.put("nsp_ts", System.currentTimeMillis() + "");
form.put("access_token", authToken.getAccessToken());
form.put("nsp_svc", "GOpen.User.getInfo");
form.put("getNickName", "1");
String response = HttpUtil.post(source.userInfo(), form);
log.info(response);
JSONObject object = JSONObject.parseObject(response);
this.checkResponse(object);
AuthUserGender gender = getRealGender(object);
return AuthUser.builder()
.rawUserInfo(object)
.uuid(object.getString("unionID"))
.username(object.getString("displayName"))
.nickname(object.getString("displayName"))
.gender(gender)
.avatar(object.getString("headPictureURL"))
.mobileNumber(object.getString("mobileNumber"))
.email(object.getString("email"))
.token(authToken)
.source(source.toString())
.build();
}
/**
* 刷新access token 续期
*
* @param authToken 登录成功后返回的Token信息
* @return AuthResponse
*/
@Override
public AjaxResult refresh(AuthToken authToken) {
Map<String, Object> form = new HashMap<>(8);
form.put("client_id", config.getClientId());
form.put("client_secret", config.getClientSecret());
form.put("refresh_token", authToken.getRefreshToken());
form.put("grant_type", "refresh_token");
String response = HttpUtil.post(source.refresh(), form);
return AjaxResult.success(getAuthToken(response));
}
private AuthToken getAuthToken(String response) {
JSONObject object = JSONObject.parseObject(response);
this.checkResponse(object);
return AuthToken.builder()
.accessToken(object.getString("access_token"))
.expireIn(object.getIntValue("expires_in"))
.refreshToken(object.getString("refresh_token"))
.scope(object.getString("scope"))
.tokenType(object.getString("token_type"))
.idToken(object.getString("id_token"))
.build();
}
/**
* 返回带{@code state}参数的授权url授权回调时会带上这个{@code state}
*
* @param state state 验证授权流程的参数可以防止csrf
* @return 返回授权地址
*/
@Override
public String authorize(String state) {
Map<String, Object> form = new HashMap<>(8);
form.put("client_id", config.getClientId());
form.put("client_secret", config.getClientSecret());
form.put("redirect_uri", config.getRedirectUri());
form.put("state", getRealState(state));
form.put("response_type", "code");
form.put("access_type", "offline");
form.put("scope", this.getScopes(" ", true, AuthScopeUtils.getDefaultScopes(AuthHuaweiScope.values())));
return HttpUtil.get(source.authorize(), form);
}
/**
* 获取用户的实际性别华为系统中用户的性别1表示女0表示男
*
* @param object obj
* @return AuthUserGender
*/
private AuthUserGender getRealGender(JSONObject object) {
int genderCodeInt = object.getIntValue("gender");
String genderCode = genderCodeInt == 0 ? "0" : (genderCodeInt == 1) ? "1" : genderCodeInt + "";
return AuthUserGender.getRealGender(genderCode);
}
/**
* 校验响应结果
*
* @param object 接口返回的结果
*/
private void checkResponse(JSONObject object) {
if (object.containsKey("NSP_STATUS")) {
throw new AuthException(object.getString("error"));
}
if (object.containsKey("error")) {
throw new AuthException(object.getString("sub_error") + ":" + object.getString("error_description"));
}
}
}

View File

@ -0,0 +1,76 @@
package com.sf.oauth.request;
import com.sf.common.constant.HttpStatus;
import com.sf.common.core.domain.AjaxResult;
import com.sf.oauth.domain.AuthUser;
import com.sf.oauth.exception.AuthException;
import com.sf.oauth.domain.AuthCallback;
import com.sf.oauth.domain.AuthToken;
/**
* {@code Request}公共接口所有平台的{@code Request}都需要实现该接口
* <p>
* {@link AuthRequest#authorize()}
* {@link AuthRequest#authorize(String)}
* {@link AuthRequest#callback(AuthCallback)}
* {@link AuthRequest#revoke(AuthToken)}
* {@link AuthRequest#refresh(AuthToken)}
*
* @author zoukun
*/
public interface AuthRequest {
/**
* 返回授权url可自行跳转页面
* <p>
* 不建议使用该方式获取授权地址不带{@code state}的授权地址容易受到csrf攻击
* 建议使用{@link AuthDefaultRequest#authorize(String)}方法生成授权地址在回调方法中对{@code state}进行校验
*
* @return 返回授权地址
*/
@Deprecated
default String authorize() {
throw new AuthException(HttpStatus.UNAUTHORIZED,"Not Implemented");
}
/**
* 返回带{@code state}参数的授权url授权回调时会带上这个{@code state}
*
* @param state state 验证授权流程的参数可以防止csrf
* @return 返回授权地址
*/
default String authorize(String state) {
throw new AuthException(HttpStatus.UNAUTHORIZED,"Not Implemented");
}
/**
* 第三方登录
*
* @param authCallback 用于接收回调参数的实体
* @return 返回登录成功后的用户信息
*/
default AuthUser callback(AuthCallback authCallback) {
throw new AuthException(HttpStatus.UNAUTHORIZED,"Not Implemented");
}
/**
* 撤销授权
*
* @param authToken 登录成功后返回的Token信息
* @return AjaxResult
*/
default AjaxResult revoke(AuthToken authToken) {
throw new AuthException(HttpStatus.UNAUTHORIZED,"Not Implemented");
}
/**
* 刷新access token 续期
*
* @param authToken 登录成功后返回的Token信息
* @return AjaxResult
*/
default AjaxResult refresh(AuthToken authToken) {
throw new AuthException(HttpStatus.UNAUTHORIZED,"Not Implemented");
}
}

View File

@ -0,0 +1,15 @@
package com.sf.oauth.service;
import com.sf.oauth.domain.AuthUser;
import javax.servlet.http.HttpSession;
/**
* 功能描述:
*
* @author a_kun
* @date 2024/4/12 10:21
*/
public interface IAuthService {
String authLogin(AuthUser authUser, HttpSession session);
}

View File

@ -0,0 +1,62 @@
package com.sf.oauth.service.impl;
import com.sf.common.core.domain.AjaxResult;
import com.sf.common.core.domain.entity.SysUser;
import com.sf.common.enums.UserStatus;
import com.sf.common.utils.SecurityUtils;
import com.sf.common.utils.ip.IpUtils;
import com.sf.framework.web.service.SysLoginService;
import com.sf.oauth.domain.AuthUser;
import com.sf.oauth.exception.AuthException;
import com.sf.oauth.service.IAuthService;
import com.sf.system.service.ISysUserService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import javax.servlet.http.HttpSession;
import java.util.Date;
/**
* 功能描述:
*
* @author a_kun
* @date 2024/4/12 10:21
*/
@Slf4j
@Service
public class IAuthServiceImpl implements IAuthService {
@Autowired
private SysLoginService loginService;
@Autowired
private ISysUserService userService;
@Override
public String authLogin(AuthUser authUser, HttpSession session) {
// TODO 应该要登录后绑定一个平台账号没有平台账号要创建保存用户的三方来源及用户的三方唯一标识和绑定的用户
if (authUser != null) {
SysUser sysUser = new SysUser();
sysUser.setUserName(authUser.getUsername());
if (userService.checkUserNameUnique(sysUser)) {
// 注册用户后登录
sysUser.setNickName(authUser.getNickname());
sysUser.setEmail(authUser.getEmail());
sysUser.setPhonenumber(authUser.getMobileNumber());
sysUser.setSex(authUser.getGender().getCode());
sysUser.setAvatar(authUser.getAvatar());
sysUser.setPassword(SecurityUtils.encryptPassword("ztzh@sac123"));
sysUser.setStatus(UserStatus.OK.getCode());
sysUser.setDelFlag("0");
sysUser.setLoginIp(IpUtils.getHostIp());
sysUser.setLoginDate(new Date());
userService.insertUser(sysUser);
}
// 生成令牌
return loginService.noPwdLogin(authUser.getUsername(), session);
}
throw new AuthException("login error");
}
}

View File

@ -0,0 +1,79 @@
package com.sf.oauth.utils;
import cn.hutool.core.util.StrUtil;
import com.sf.common.constant.HttpStatus;
import com.sf.oauth.config.AuthConfig;
import com.sf.oauth.enums.AuthDefaultSource;
import com.sf.oauth.config.AuthSource;
import com.sf.oauth.exception.AuthException;
import com.sf.oauth.domain.AuthCallback;
/**
* 授权配置类的校验器
*
* @author ZK
*/
public class AuthChecker {
/**
* 是否支持第三方登录
*
* @param config config
* @param source source
* @return true or false
*/
public static boolean isSupportedAuth(AuthConfig config, AuthSource source) {
return StrUtil.isNotEmpty(config.getClientId())
&& StrUtil.isNotEmpty(config.getClientSecret())
&& null != source;
}
/**
* 检查配置合法性针对部分平台 对redirect uri有特定要求一般来说redirect uri都是http://
* 而对于部分平台 redirect uri 必须是https的链接
*
* @param config config
* @param source source
*/
public static void checkConfig(AuthConfig config, AuthSource source) {
String redirectUri = config.getRedirectUri();
if (StrUtil.isEmpty(redirectUri)) {
throw new AuthException(HttpStatus.BAD_REQUEST, "Illegal redirect uri", source);
}
if (!AuthUtils.isHttpProtocol(redirectUri) && !AuthUtils.isHttpsProtocol(redirectUri)) {
throw new AuthException(HttpStatus.BAD_REQUEST, "Illegal redirect uri", source);
}
}
/**
* 校验回调传回的code
* <p>
* {@code v1.10.0}版本中改为传入{@code source}{@code callback}对于不同平台使用不同参数接受code的情况统一做处理
*
* @param source 当前授权平台
* @param callback 从第三方授权回调回来时传入的参数集合
*/
public static void checkCode(AuthSource source, AuthCallback callback) {
if (StrUtil.isEmpty(callback.getCode())) {
throw new AuthException(HttpStatus.UNAUTHORIZED,"Illegal code", source);
}
}
/**
* 校验回调传回的{@code state}为空或者不存在
* <p>
* {@code state}不存在的情况只有两种
* 1. {@code state}已使用被正常清除
* 2. {@code state}为前端伪造本身就不存在
*
* @param state {@code state}一定不为空
* @param source {@code source}当前授权平台
*/
public static void checkState(String state, AuthSource source) {
if (StrUtil.isEmpty(state)) {
throw new AuthException(HttpStatus.UNAUTHORIZED,"Illegal state", source);
}
}
}

View File

@ -0,0 +1,44 @@
package com.sf.oauth.utils;
import com.sf.oauth.enums.scope.AuthScope;
import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;
/**
* Scope 工具类提供对 scope 类的统一操作
*
* @author zoukun
*/
public class AuthScopeUtils {
/**
* 获取 {@link com.sf.oauth.enums.scope.AuthScope} 数组中所有的被标记为 {@code default} scope
*
* @param scopes scopes
* @return List
*/
public static List<String> getDefaultScopes(AuthScope[] scopes) {
if (null == scopes || scopes.length == 0) {
return null;
}
return Arrays.stream(scopes)
.filter((AuthScope::isDefault))
.map(AuthScope::getScope)
.collect(Collectors.toList());
}
/**
* {@link com.sf.oauth.enums.scope.AuthScope} 数组中获取实际的 scope 字符串
*
* @param scopes 可变参数支持传任意 {@link com.sf.oauth.enums.scope.AuthScope}
* @return List
*/
public static List<String> getScopes(AuthScope... scopes) {
if (null == scopes || scopes.length == 0) {
return null;
}
return Arrays.stream(scopes).map(AuthScope::getScope).collect(Collectors.toList());
}
}

View File

@ -0,0 +1,127 @@
package com.sf.oauth.utils;
import cn.hutool.core.util.StrUtil;
import com.sf.oauth.exception.AuthException;
import java.io.UnsupportedEncodingException;
import java.net.URLDecoder;
import java.net.URLEncoder;
import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;
import java.security.MessageDigest;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
public class AuthUtils {
private static final Charset DEFAULT_ENCODING;
private static final String HMAC_SHA1 = "HmacSHA1";
private static final String HMAC_SHA_256 = "HmacSHA256";
public AuthUtils() {
}
public static String urlEncode(String value) {
if (value == null) {
return "";
} else {
try {
String encoded = URLEncoder.encode(value, DEFAULT_ENCODING.displayName());
return encoded.replace("+", "%20").replace("*", "%2A").replace("~", "%7E").replace("/", "%2F");
} catch (UnsupportedEncodingException var2) {
throw new AuthException("Failed To Encode Uri", var2);
}
}
}
public static String urlDecode(String value) {
if (value == null) {
return "";
} else {
try {
return URLDecoder.decode(value, DEFAULT_ENCODING.displayName());
} catch (UnsupportedEncodingException var2) {
throw new AuthException("Failed To Decode Uri", var2);
}
}
}
public static String parseMapToString(Map<String, String> params, boolean encode) {
if (null != params && !params.isEmpty()) {
List<String> paramList = new ArrayList();
params.forEach((k, v) -> {
if (null == v) {
paramList.add(k + "=");
} else {
paramList.add(k + "=" + (encode ? urlEncode(v) : v));
}
});
return String.join("&", paramList);
} else {
return "";
}
}
public static boolean isHttpProtocol(String url) {
if (StrUtil.isEmpty(url)) {
return false;
} else {
return url.startsWith("http://") || url.startsWith("http%3A%2F%2F");
}
}
public static boolean isHttpsProtocol(String url) {
if (StrUtil.isEmpty(url)) {
return false;
} else {
return url.startsWith("https://") || url.startsWith("https%3A%2F%2F");
}
}
public static boolean isLocalHost(String url) {
return StrUtil.isEmpty(url) || url.contains("127.0.0.1") || url.contains("localhost");
}
public static boolean isHttpsProtocolOrLocalHost(String url) {
if (StrUtil.isEmpty(url)) {
return false;
} else {
return isHttpsProtocol(url) || isLocalHost(url);
}
}
public static String getTimestamp() {
return String.valueOf(System.currentTimeMillis() / 1000L);
}
public static String md5(String str) {
MessageDigest md = null;
StringBuilder buffer = null;
try {
md = MessageDigest.getInstance("MD5");
md.update(str.getBytes(StandardCharsets.UTF_8));
byte[] byteData = md.digest();
buffer = new StringBuilder();
byte[] var4 = byteData;
int var5 = byteData.length;
for(int var6 = 0; var6 < var5; ++var6) {
byte byteDatum = var4[var6];
buffer.append(Integer.toString((byteDatum & 255) + 256, 16).substring(1));
}
} catch (Exception var8) {
}
return null == buffer ? "" : buffer.toString();
}
static {
DEFAULT_ENCODING = StandardCharsets.UTF_8;
}
}

33
sf-order/pom.xml Normal file
View File

@ -0,0 +1,33 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<artifactId>smarterFramework</artifactId>
<groupId>com.smarterFramework</groupId>
<version>1.0.0</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>sf-order</artifactId>
<description>
订单模块
</description>
<dependencies>
<!-- 通用工具-->
<dependency>
<groupId>com.smarterFramework</groupId>
<artifactId>sf-common</artifactId>
</dependency>
<dependency>
<groupId>com.smarterFramework</groupId>
<artifactId>sf-framework</artifactId>
</dependency>
</dependencies>
</project>

View File

@ -0,0 +1,115 @@
package com.sf.order.controller;
import com.sf.common.annotation.Log;
import com.sf.common.core.controller.BaseController;
import com.sf.common.core.domain.AjaxResult;
import com.sf.common.core.page.TableDataInfo;
import com.sf.common.enums.BusinessType;
import com.sf.common.enums.RequestHeaderEnums;
import com.sf.common.utils.http.RequestUtils;
import com.sf.common.utils.poi.ExcelUtil;
import com.sf.order.domain.OrderInfo;
import com.sf.order.domain.dto.OrderCreateDto;
import com.sf.order.domain.req.OrderListReqVo;
import com.sf.order.domain.res.OrderListResVo;
import com.sf.order.service.IOrderInfoService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import javax.servlet.http.HttpServletResponse;
import java.util.List;
/**
* 订单基础信息Controller
*
* @author ztzh
* @date 2024-04-09
*/
@RestController
@RequestMapping("/order")
public class OrderInfoController extends BaseController {
@Autowired
private IOrderInfoService orderInfoService;
/**
* 查询订单基础信息列表
*/
@GetMapping("/list")
public TableDataInfo list(OrderListReqVo vo) {
vo.setAppCode(RequestUtils.getHeader(RequestHeaderEnums.APP_CODE.getCode()));
startPage();
List<OrderListResVo> list = orderInfoService.queryList(vo);
return getDataTable(list);
}
/**
* 我的订单列表当前用户
*/
@GetMapping("/myOrderList")
public TableDataInfo myOrderList(OrderListReqVo vo) {
vo.setAppCode(RequestUtils.getHeader(RequestHeaderEnums.APP_CODE.getCode()));
vo.setUserId(getUserId());
// startPage();
List<OrderListResVo> list = orderInfoService.queryList(vo);
return getDataTable(list);
}
/**
* 导出订单基础信息列表
*/
@Log(title = "订单基础信息", businessType = BusinessType.EXPORT)
@PostMapping("/export")
public void export(HttpServletResponse response, OrderInfo orderInfo) {
List<OrderInfo> list = orderInfoService.selectOrderInfoList(orderInfo);
ExcelUtil<OrderInfo> util = new ExcelUtil<OrderInfo>(OrderInfo.class);
util.exportExcel(response, list, "订单基础信息数据");
}
/**
* 获取订单基础信息详细信息
*/
@GetMapping(value = "/{id}")
public AjaxResult getInfo(@PathVariable("id") Long id) {
return success(orderInfoService.selectOrderInfoById(id));
}
/**
* 新增订单基础信息
*/
@Log(title = "创建订单基础信息", businessType = BusinessType.INSERT)
@PostMapping(value = "/createOrder")
public AjaxResult createOrder(@RequestBody OrderCreateDto orderCreateDto) {
orderCreateDto.setAppCode(RequestUtils.getHeader(RequestHeaderEnums.APP_CODE.getCode()));
return AjaxResult.success(orderInfoService.createOrder(orderCreateDto));
}
/**
* 修改订单基础信息
*/
@Log(title = "订单基础信息", businessType = BusinessType.UPDATE)
@PutMapping
public AjaxResult edit(@RequestBody OrderInfo orderInfo) {
return toAjax(orderInfoService.updateOrderInfo(orderInfo));
}
/**
* 支付订单
*/
@PostMapping(value = "/pay/{orderId}")
private String orderPay(@PathVariable(value = "orderId") Long orderId) {
orderInfoService.orderPay(orderId);
return null;
}
/**
* 删除订单基础信息
*/
@Log(title = "订单基础信息", businessType = BusinessType.DELETE)
@DeleteMapping("/{ids}")
public AjaxResult remove(@PathVariable Long[] ids) {
return toAjax(orderInfoService.deleteOrderInfoByIds(ids));
}
}

View File

@ -0,0 +1,187 @@
package com.sf.order.domain;
import com.fasterxml.jackson.annotation.JsonFormat;
import com.sf.common.annotation.Excel;
import com.sf.common.core.domain.BaseEntity;
import lombok.Data;
import org.apache.commons.lang3.builder.ToStringBuilder;
import org.apache.commons.lang3.builder.ToStringStyle;
import java.util.Date;
/**
* 订单基础信息对象 ORDER_INFO
*
* @author ztzh
* @date 2024-04-09
*/
@Data
public class OrderInfo extends BaseEntity {
private static final long serialVersionUID = 1L;
/**
* 主键
*/
private Long id;
/**
* 订单编号
*/
@Excel(name = "订单编号")
private Long orderNo;
/**
* 订单状态: 订单状态: 0:待支付 1:已付款 2:支付超时系统结束 3:客户自主取消 4:已完成
*/
@Excel(name = "订单状态: 0:待支付 1:已付款 2:支付超时系统结束 3:客户自主取消 4:已完成")
private Long orderStatus;
/**
* 支付方式:0-点券 1-现金
*/
@Excel(name = "支付方式:0-点券 1-现金")
private Long payType;
/**
* 支付渠道(支付方式为现金时)
* 0:微信
* 1:支付宝
*/
@Excel(name = "支付渠道(支付方式为现金时) 0:微信 1:支付宝")
private Long payChannel;
/**
* 订单金额
*/
@Excel(name = "订单金额")
private Long orderAmt;
/**
* 运费
*/
@Excel(name = "运费")
private Long freightAmt;
/**
* 总金额
*/
@Excel(name = "总金额")
private Long payAmt;
/**
* 实际支付金额
*/
@Excel(name = "实际支付金额")
private Long reallyAmt;
/**
* 收件方式
* 0-自提
* 1-快递 2-配送
*/
@Excel(name = "收件方式0-自提 1-快递 2-配送")
private Long receiveType;
/**
* 商品Id
*/
@Excel(name = "商品Id")
private Long goodsId;
/**
* 商户Id
*/
@Excel(name = "商户Id")
private Long businessId;
/**
* 收货地址配置Id
*/
@Excel(name = "收货地址配置Id")
private Long receiveAddrId;
/**
* 支付时间
*/
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
@Excel(name = "支付时间", width = 30, dateFormat = "yyyy-MM-dd HH:mm:ss")
private Date payTime;
/**
* 订单创建人
*/
@Excel(name = "订单创建人")
private Long createUserId;
/**
* 最后一次更新操作人
*/
@Excel(name = "最后一次更新操作人")
private Long updateUserId;
/**
* 逻辑删除标识
* 0:未删除
* 1:已删除
*/
@Excel(name = "逻辑删除标识 0:未删除 1:已删除")
private Long isDelete;
/**
* 快递单号
*/
@Excel(name = "快递单号")
private String trackNo;
/**
* 订单类型0:自动1:手动
*/
@Excel(name = "订单类型0:自动1:手动")
private Long orderType;
/**
* 平台外部订单号
*/
@Excel(name = "平台外部订单号")
private String outOrderNo;
/**
* 平台支付返回值
*/
@Excel(name = "平台支付返回值")
private String payData;
/**
* 减免金额(优惠券抵扣)
*/
@Excel(name = "减免金额(优惠券抵扣)")
private Long reductionAmout;
/**
* * 商品数量
*/
private Integer goodsCount;
/**
* * 商品类型
* * 0消耗型商品
* * 1非消耗型商品
* * 2自动续期订阅商品
*/
private Integer goodsType;
/**
* 商品单价
*/
private Long goodsPrice;
/**
* 商品编号
*/
private String goodsCode;
/**
* appCode
*/
private String appCode;
}

View File

@ -0,0 +1,80 @@
package com.sf.order.domain.dto;
import io.swagger.v3.oas.annotations.media.Schema;
import javax.validation.constraints.NotNull;
/**
* @author : ztzh
* @since : 2023/7/27
*/
@Schema(description = "下单")
public class OrderCreateDto {
@Schema(description = "商品id")
@NotNull(message = "商品id不能为空")
private Long goodsId;
@Schema(description = "平台外部订单号")
private String outOrderNo;
@Schema(description = "数量")
private Long count;
@Schema(description = "金额")
private Long amount;
@Schema(description = "用户id")
@NotNull(message = "用户id不能空")
private Long userId;
@Schema(description = "应用code")
@NotNull(message = "应用code不能空")
private String appCode;
public Long getGoodsId() {
return goodsId;
}
public void setGoodsId(Long goodsId) {
this.goodsId = goodsId;
}
public Long getCount() {
return count;
}
public void setCount(Long count) {
this.count = count;
}
public Long getAmount() {
return amount;
}
public void setAmount(Long amount) {
this.amount = amount;
}
public Long getUserId() {
return userId;
}
public void setUserId(Long userId) {
this.userId = userId;
}
public String getOutOrderNo() {
return outOrderNo;
}
public void setOutOrderNo(String outOrderNo) {
this.outOrderNo = outOrderNo;
}
public String getAppCode() {
return appCode;
}
public void setAppCode(String appCode) {
this.appCode = appCode;
}
}

View File

@ -0,0 +1,27 @@
package com.sf.order.domain.req;
import com.sf.common.core.domain.BaseEntity;
import lombok.Data;
@Data
public class OrderListReqVo extends BaseEntity {
private static final long serialVersionUID = 1L;
/**
* 主键id
*/
private Long userId;
/**
* 订单状态
*/
private Long orderStatus;
private Integer pageSize;
private Integer pageNo;
private String appCode;
}

View File

@ -0,0 +1,97 @@
package com.sf.order.domain.res;
import com.fasterxml.jackson.annotation.JsonFormat;
import com.sf.common.annotation.Excel;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
import java.util.Date;
/**
* 活动信息详情
*
*/
@Data
@Schema(name = "OrderListResVo", description = "订单列表")
public class OrderListResVo {
/**
* 主键id
*/
private Long id;
/**
* 订单编号
*/
private String orderNo;
/**
* 订单状态: 0:待支付 1:已付款待发货 2:配送中 3:待取货 4:支付超时系统结束 5:客户自主取消 6:已完成
*/
private Long orderStatus;
/**
* 订单金额
*/
private Long orderAmt;
/**
* 支付时间
*/
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
private Date payTime;
/**
* 订阅订单取消时间
*/
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
private Date subscriptionCancellationTime;
/**
* 商品标题
*/
private String productTitle;
/**
* 图片
*/
private String productPicture;
/**
* 商品描述
*/
private String productDesc;
/**
* 商品规格
*/
private String goodsSpec;
/**
* 商品数量
*/
private Integer goodsCount;
/**
* 商品价格
*/
private Long goodsPrice;
/**
* * 商品类型
* * 0消耗型商品
* * 1非消耗型商品
* * 2自动续期订阅商品
*/
private Integer goodsType;
/**
* 商品编码
*/
private String goodsCode;
/**
* 应用编码
*/
private String appCode;
}

View File

@ -0,0 +1,69 @@
package com.sf.order.mapper;
import com.sf.order.domain.OrderInfo;
import com.sf.order.domain.req.OrderListReqVo;
import com.sf.order.domain.res.OrderListResVo;
import java.util.List;
/**
* 订单基础信息Mapper接口
*
* @author ztzh
* @date 2024-04-09
*/
public interface OrderInfoMapper {
/**
* 查询订单基础信息
*
* @param id 订单基础信息主键
* @return 订单基础信息
*/
public OrderInfo selectOrderInfoById(Long id);
/**
* 查询订单基础信息列表
*
* @param orderInfo 订单基础信息
* @return 订单基础信息集合
*/
public List<OrderInfo> selectOrderInfoList(OrderInfo orderInfo);
List<OrderListResVo> queryList(OrderListReqVo vo);
/**
* 新增订单基础信息
*
* @param orderInfo 订单基础信息
* @return 结果
*/
public int insertOrderInfo(OrderInfo orderInfo);
/**
* 修改订单基础信息
*
* @param orderInfo 订单基础信息
* @return 结果
*/
public int updateOrderInfo(OrderInfo orderInfo);
/**
* 删除订单基础信息
*
* @param id 订单基础信息主键
* @return 结果
*/
public int deleteOrderInfoById(Long id);
/**
* 批量删除订单基础信息
*
* @param ids 需要删除的数据主键集合
* @return 结果
*/
public int deleteOrderInfoByIds(Long[] ids);
OrderInfo selectOrderInfoByOrderNo(String orderNo);
}

View File

@ -0,0 +1,78 @@
package com.sf.order.service;
import com.sf.order.domain.OrderInfo;
import com.sf.order.domain.dto.OrderCreateDto;
import com.sf.order.domain.req.OrderListReqVo;
import com.sf.order.domain.res.OrderListResVo;
import java.util.List;
/**
* 订单基础信息Service接口
*
* @author ztzh
* @date 2024-04-09
*/
public interface IOrderInfoService
{
/**
* 查询订单基础信息
*
* @param id 订单基础信息主键
* @return 订单基础信息
*/
public OrderInfo selectOrderInfoById(Long id);
/**
* 查询订单基础信息列表
*
* @param orderInfo 订单基础信息
* @return 订单基础信息集合
*/
public List<OrderInfo> selectOrderInfoList(OrderInfo orderInfo);
/**
* 查询订单基础信息列表
*/
List<OrderListResVo> queryList(OrderListReqVo vo);
/**
* 新增订单基础信息
*
* @param orderInfo 订单基础信息
* @return 结果
*/
public Long createOrder(OrderCreateDto orderInfo);
/**
* 修改订单基础信息
*
* @param orderInfo 订单基础信息
* @return 结果
*/
public int updateOrderInfo(OrderInfo orderInfo);
/**
* 批量删除订单基础信息
*
* @param ids 需要删除的订单基础信息主键集合
* @return 结果
*/
public int deleteOrderInfoByIds(Long[] ids);
/**
* 删除订单基础信息信息
*
* @param id 订单基础信息主键
* @return 结果
*/
public int deleteOrderInfoById(Long id);
void orderPay(Long orderId);
OrderInfo selectOrderInfoByOrderNo(String orderNo);
void insertOrder(OrderInfo orderInfo);
}

View File

@ -0,0 +1,145 @@
package com.sf.order.service.impl;
import com.sf.common.exception.ServiceException;
import com.sf.common.utils.DateUtils;
import com.sf.common.utils.SnowflakeIdWorker;
import com.sf.order.domain.OrderInfo;
import com.sf.order.domain.dto.OrderCreateDto;
import com.sf.order.domain.req.OrderListReqVo;
import com.sf.order.domain.res.OrderListResVo;
import com.sf.order.mapper.OrderInfoMapper;
import com.sf.order.service.IOrderInfoService;
import org.springframework.stereotype.Service;
import javax.annotation.Resource;
import java.util.List;
/**
* 订单基础信息Service业务层处理
*
* @author ztzh
* @date 2024-04-09
*/
@Service
public class OrderInfoServiceImpl implements IOrderInfoService {
@Resource
private OrderInfoMapper orderInfoMapper;
@Resource
private SnowflakeIdWorker snowflakeIdWorker;
/**
* 查询订单基础信息
*
* @param id 订单基础信息主键
* @return 订单基础信息
*/
@Override
public OrderInfo selectOrderInfoById(Long id) {
return orderInfoMapper.selectOrderInfoById(id);
}
/**
* 查询订单基础信息列表
*
* @param orderInfo 订单基础信息
* @return 订单基础信息
*/
@Override
public List<OrderInfo> selectOrderInfoList(OrderInfo orderInfo) {
return orderInfoMapper.selectOrderInfoList(orderInfo);
}
public List<OrderListResVo> queryList(OrderListReqVo vo) {
return orderInfoMapper.queryList(vo);
}
/**
* 新增订单基础信息
*
* @param orderCreateDto 订单基础信息
* @return 结果
*/
@Override
public Long createOrder(OrderCreateDto orderCreateDto) {
OrderInfo orderInfo = new OrderInfo();
long id = snowflakeIdWorker.nextId();
orderInfo.setOrderNo(id);
orderInfo.setPayType(1L);
orderInfo.setReceiveType(0L);
orderInfo.setOrderStatus(0L);
orderInfo.setCreateUserId(orderCreateDto.getUserId());
orderInfo.setUpdateUserId(orderCreateDto.getUserId());
orderInfo.setGoodsId(orderCreateDto.getGoodsId());
orderInfo.setOrderAmt(orderCreateDto.getAmount());
orderInfo.setPayAmt(orderCreateDto.getAmount());
orderInfo.setCreateTime(DateUtils.getNowDate());
orderInfo.setUpdateTime(DateUtils.getNowDate());
orderInfo.setOutOrderNo(orderCreateDto.getOutOrderNo());
orderInfo.setAppCode(orderCreateDto.getAppCode());
orderInfoMapper.insertOrderInfo(orderInfo);
return id;
}
/**
* 修改订单基础信息
*
* @param orderInfo 订单基础信息
* @return 结果
*/
@Override
public int updateOrderInfo(OrderInfo orderInfo) {
orderInfo.setUpdateTime(DateUtils.getNowDate());
return orderInfoMapper.updateOrderInfo(orderInfo);
}
@Override
public void orderPay(Long orderId) {
OrderInfo updateOrder = this.selectOrderInfoById(orderId);
if (updateOrder == null) {
throw new ServiceException("订单缺失!");
}
// if (!OrderInfoConstant.ORDER_WAITING_FOR_PAYMENT.equals(orderInfo.getOrderStatus())) {
// throw new ServiceException("订单状态异常!");
// }
updateOrder.setOrderStatus(1L);
updateOrder.setPayTime(DateUtils.getNowDate());
// 修改订单状态
if (1 > this.updateOrderInfo(updateOrder)) {
throw new ServiceException("支付异常,请联系管理员!");
}
}
@Override
public OrderInfo selectOrderInfoByOrderNo(String orderNo) {
return orderInfoMapper.selectOrderInfoByOrderNo(orderNo);
}
@Override
public void insertOrder(OrderInfo orderInfo) {
orderInfoMapper.insertOrderInfo(orderInfo);
}
/**
* 批量删除订单基础信息
*
* @param ids 需要删除的订单基础信息主键
* @return 结果
*/
@Override
public int deleteOrderInfoByIds(Long[] ids) {
return orderInfoMapper.deleteOrderInfoByIds(ids);
}
/**
* 删除订单基础信息信息
*
* @param id 订单基础信息主键
* @return 结果
*/
@Override
public int deleteOrderInfoById(Long id) {
return orderInfoMapper.deleteOrderInfoById(id);
}
}

View File

@ -0,0 +1,211 @@
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.sf.order.mapper.OrderInfoMapper">
<resultMap type="OrderInfo" id="OrderInfoResult">
<result property="id" column="id" />
<result property="orderNo" column="order_no" />
<result property="orderStatus" column="order_status" />
<result property="payType" column="pay_type" />
<result property="payChannel" column="pay_channel" />
<result property="orderAmt" column="order_amt" />
<result property="freightAmt" column="freight_amt" />
<result property="payAmt" column="pay_amt" />
<result property="reallyAmt" column="really_amt" />
<result property="receiveType" column="receive_type" />
<result property="goodsId" column="goods_id" />
<result property="businessId" column="business_id" />
<result property="receiveAddrId" column="receive_addr_id" />
<result property="createTime" column="create_time" />
<result property="payTime" column="pay_time" />
<result property="createUserId" column="create_user_id" />
<result property="updateUserId" column="update_user_id" />
<result property="isDelete" column="is_delete" />
<result property="updateTime" column="update_time" />
<result property="trackNo" column="track_no" />
<result property="orderType" column="order_type" />
<result property="outOrderNo" column="out_order_no" />
<result property="payData" column="pay_data" />
<result property="reductionAmout" column="reduction_amout" />
</resultMap>
<resultMap type="OrderListResVo" id="OrderListResVo">
<result property="id" column="id" />
<result property="orderNo" column="order_no" />
<result property="orderStatus" column="order_status" />
<result property="orderAmt" column="order_amt" />
<result property="payTime" column="pay_time" />
<result property="productTitle" column="product_title" />
<result property="productPicture" column="product_picture" />
<result property="productDesc" column="product_desc" />
<result property="goodsSpec" column="goods_spec" />
<result property="goodsCount" column="goods_count" />
<result property="subscriptionCancellationTime" column="subscription_cancellation_time" />
<result property="goodsType" column="goods_type" />
<result property="goodsPrice" column="goods_price" />
<result property="goodsCode" column="goods_code" />
<result property="appCode" column="app_code" />
</resultMap>
<sql id="selectOrderInfoVo">
select id, order_no, order_status, pay_type, pay_channel, order_amt, freight_amt, pay_amt, really_amt, receive_type, goods_id, business_id, receive_addr_id, create_time, pay_time, create_user_id, update_user_id, is_delete, update_time, track_no, order_type, out_order_no, pay_data, reduction_amout from Order_info
</sql>
<sql id="OrderListInfoVo">
SELECT a.id,a.app_code,a.order_no,a.order_status,a.order_amt,a.pay_time,a.goods_count,a.subscription_cancellation_time,a.goods_type,a.goods_price,a.goods_code,b.product_title,b.product_picture,b.product_desc,b.goods_spec
FROM Order_info a LEFT JOIN GOODS_MESSAGES b ON a.goods_id = b.id
</sql>
<select id="selectOrderInfoList" parameterType="OrderInfo" resultMap="OrderInfoResult">
<include refid="selectOrderInfoVo"/>
<where>
<if test="orderNo != null "> and order_no = #{orderNo}</if>
<if test="orderStatus != null "> and order_status = #{orderStatus}</if>
<if test="payType != null "> and pay_type = #{payType}</if>
<if test="payChannel != null "> and pay_channel = #{payChannel}</if>
<if test="orderAmt != null "> and order_amt = #{orderAmt}</if>
<if test="freightAmt != null "> and freight_amt = #{freightAmt}</if>
<if test="payAmt != null "> and pay_amt = #{payAmt}</if>
<if test="reallyAmt != null "> and really_amt = #{reallyAmt}</if>
<if test="receiveType != null "> and receive_type = #{receiveType}</if>
<if test="goodsId != null "> and goods_id = #{goodsId}</if>
<if test="businessId != null "> and business_id = #{businessId}</if>
<if test="receiveAddrId != null "> and receive_addr_id = #{receiveAddrId}</if>
<if test="payTime != null "> and pay_time = #{payTime}</if>
<if test="createUserId != null "> and create_user_id = #{createUserId}</if>
<if test="updateUserId != null "> and update_user_id = #{updateUserId}</if>
<if test="isDelete != null "> and is_delete = #{isDelete}</if>
<if test="trackNo != null and trackNo != ''"> and track_no = #{trackNo}</if>
<if test="orderType != null "> and order_type = #{orderType}</if>
<if test="outOrderNo != null "> and out_order_no = #{outOrderNo}</if>
<if test="payData != null and payData != ''"> and pay_data = #{payData}</if>
<if test="reductionAmout != null "> and reduction_amout = #{reductionAmout}</if>
</where>
</select>
<select id="queryList" parameterType="OrderListReqVo" resultMap="OrderListResVo">
<include refid="OrderListInfoVo"/>
<where>
<if test="appCode != null "> and a.app_code = #{appCode}</if>
<if test="orderStatus != null "> and a.order_status = #{orderStatus}</if>
<if test="userId != null "> and a.create_user_id = #{userId}</if>
</where>
ORDER BY a.create_time DESC
</select>
<select id="selectOrderInfoById" parameterType="Long" resultMap="OrderInfoResult">
<include refid="selectOrderInfoVo"/>
where id = #{id}
</select>
<select id="selectOrderInfoByOrderNo" resultMap="OrderInfoResult">
<include refid="selectOrderInfoVo"/>
where order_no = #{orderNo}
</select>
<insert id="insertOrderInfo" parameterType="OrderInfo">
insert into Order_info
<trim prefix="(" suffix=")" suffixOverrides=",">
<if test="id != null">id,</if>
<if test="orderNo != null">order_no,</if>
<if test="orderStatus != null">order_status,</if>
<if test="payType != null">pay_type,</if>
<if test="payChannel != null">pay_channel,</if>
<if test="orderAmt != null">order_amt,</if>
<if test="freightAmt != null">freight_amt,</if>
<if test="payAmt != null">pay_amt,</if>
<if test="reallyAmt != null">really_amt,</if>
<if test="receiveType != null">receive_type,</if>
<if test="goodsId != null">goods_id,</if>
<if test="businessId != null">business_id,</if>
<if test="receiveAddrId != null">receive_addr_id,</if>
<if test="createTime != null">create_time,</if>
<if test="payTime != null">pay_time,</if>
<if test="createUserId != null">create_user_id,</if>
<if test="updateUserId != null">update_user_id,</if>
<if test="isDelete != null">is_delete,</if>
<if test="updateTime != null">update_time,</if>
<if test="trackNo != null">track_no,</if>
<if test="orderType != null">order_type,</if>
<if test="outOrderNo != null">out_order_no,</if>
<if test="payData != null">pay_data,</if>
<if test="reductionAmout != null">reduction_amout,</if>
<if test="goodsCount != null">goods_count,</if>
<if test="goodsType != null">goods_type,</if>
<if test="goodsPrice != null">goods_price,</if>
<if test="goodsCode != null">goods_code,</if>
<if test="appCode != null">app_code,</if>
</trim>
<trim prefix="values (" suffix=")" suffixOverrides=",">
<if test="id != null">#{id},</if>
<if test="orderNo != null">#{orderNo},</if>
<if test="orderStatus != null">#{orderStatus},</if>
<if test="payType != null">#{payType},</if>
<if test="payChannel != null">#{payChannel},</if>
<if test="orderAmt != null">#{orderAmt},</if>
<if test="freightAmt != null">#{freightAmt},</if>
<if test="payAmt != null">#{payAmt},</if>
<if test="reallyAmt != null">#{reallyAmt},</if>
<if test="receiveType != null">#{receiveType},</if>
<if test="goodsId != null">#{goodsId},</if>
<if test="businessId != null">#{businessId},</if>
<if test="receiveAddrId != null">#{receiveAddrId},</if>
<if test="createTime != null">#{createTime},</if>
<if test="payTime != null">#{payTime},</if>
<if test="createUserId != null">#{createUserId},</if>
<if test="updateUserId != null">#{updateUserId},</if>
<if test="isDelete != null">#{isDelete},</if>
<if test="updateTime != null">#{updateTime},</if>
<if test="trackNo != null">#{trackNo},</if>
<if test="orderType != null">#{orderType},</if>
<if test="outOrderNo != null">#{outOrderNo},</if>
<if test="payData != null">#{payData},</if>
<if test="reductionAmout != null">#{reductionAmout},</if>
<if test="goodsCount != null">#{goodsCount},</if>
<if test="goodsType != null">#{goodsType},</if>
<if test="goodsPrice != null">#{goodsPrice},</if>
<if test="goodsCode != null">#{goodsCode},</if>
<if test="appCode != null">#{appCode},</if>
</trim>
</insert>
<update id="updateOrderInfo" parameterType="OrderInfo">
update Order_info
<trim prefix="SET" suffixOverrides=",">
<if test="orderNo != null">order_no = #{orderNo},</if>
<if test="orderStatus != null">order_status = #{orderStatus},</if>
<if test="payType != null">pay_type = #{payType},</if>
<if test="payChannel != null">pay_channel = #{payChannel},</if>
<if test="orderAmt != null">order_amt = #{orderAmt},</if>
<if test="freightAmt != null">freight_amt = #{freightAmt},</if>
<if test="payAmt != null">pay_amt = #{payAmt},</if>
<if test="reallyAmt != null">really_amt = #{reallyAmt},</if>
<if test="receiveType != null">receive_type = #{receiveType},</if>
<if test="goodsId != null">goods_id = #{goodsId},</if>
<if test="businessId != null">business_id = #{businessId},</if>
<if test="receiveAddrId != null">receive_addr_id = #{receiveAddrId},</if>
<if test="createTime != null">create_time = #{createTime},</if>
<if test="payTime != null">pay_time = #{payTime},</if>
<if test="createUserId != null">create_user_id = #{createUserId},</if>
<if test="updateUserId != null">update_user_id = #{updateUserId},</if>
<if test="isDelete != null">is_delete = #{isDelete},</if>
<if test="updateTime != null">update_time = #{updateTime},</if>
<if test="trackNo != null">track_no = #{trackNo},</if>
<if test="orderType != null">order_type = #{orderType},</if>
<if test="outOrderNo != null">out_order_no = #{outOrderNo},</if>
<if test="payData != null">pay_data = #{payData},</if>
<if test="reductionAmout != null">reduction_amout = #{reductionAmout},</if>
</trim>
where id = #{id}
</update>
<delete id="deleteOrderInfoById" parameterType="Long">
delete from Order_info where id = #{id}
</delete>
<delete id="deleteOrderInfoByIds" parameterType="String">
delete from Order_info where id in
<foreach item="id" collection="array" open="(" separator="," close=")">
#{id}
</foreach>
</delete>
</mapper>

50
sf-payment/pom.xml Normal file
View File

@ -0,0 +1,50 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<artifactId>smarterFramework</artifactId>
<groupId>com.smarterFramework</groupId>
<version>1.0.0</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>sf-payment</artifactId>
<description>
支付模块
</description>
<dependencies>
<!-- 通用工具-->
<dependency>
<groupId>com.smarterFramework</groupId>
<artifactId>sf-common</artifactId>
</dependency>
<dependency>
<groupId>com.smarterFramework</groupId>
<artifactId>sf-framework</artifactId>
</dependency>
<dependency>
<groupId>com.smarterFramework</groupId>
<artifactId>sf-order</artifactId>
</dependency>
<dependency>
<groupId>com.smarterFramework</groupId>
<artifactId>sf-service</artifactId>
</dependency>
<dependency>
<groupId>org.bouncycastle</groupId>
<artifactId>bcprov-jdk18on</artifactId>
<version>1.73</version>
</dependency>
<dependency>
<groupId>com.auth0</groupId>
<artifactId>java-jwt</artifactId>
<version>4.4.0</version>
</dependency>
</dependencies>
</project>

View File

@ -0,0 +1,37 @@
package com.sf.payment.config;
import lombok.Data;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Configuration;
/**
* 功能描述:
*
* @author a_kun
* @date 2024/4/17 9:23
*/
@Data
@Configuration
public class HuaweiPaymentConfig {
/**
* 客户端idoauth用
*/
@Value("${huawei.payment.clientId:110693217}")
private String clientId;
/**
* 客户端Secret对应各平台的appSecret
*/
@Value("${huawei.payment.clientSecret:1410c01bc71c7ba587175ae79e500137c70945acc1416a38127cf98a09a6f8ba}")
private String clientSecret;
/**
* 应用id
*/
@Value("${huawei.payment.appId:5765880207854169373}")
private String appId;
}

View File

@ -0,0 +1,29 @@
package com.sf.payment.constant;
import io.jsonwebtoken.Claims;
/**
* 商品信息
*
* @author zoukun
*/
public class GoodsConstants {
/**
* 商品类型
* 0消耗型商品
*/
public static final Integer GOODS_TYPE_CONSUMABLE = 0;
/**
* 商品类型
* 1非消耗型商品
*/
public static final Integer GOODS_TYPE_NON_CONSUMABLE = 1;
/**
* 商品类型
* 2自动续期订阅商品
*/
public static final Integer GOODS_TYPE_AUTOMATIC_RENEWAL_SUBSCRIPTION = 2;
}

View File

@ -0,0 +1,48 @@
package com.sf.payment.controller;
import com.alibaba.fastjson2.JSONObject;
import com.sf.common.core.domain.AjaxResult;
import com.sf.payment.constant.GoodsConstants;
import com.sf.payment.domain.HuaweiPaymentCallback;
import com.sf.payment.domain.HuaweiPurchasesVerifyDTO;
import com.sf.payment.service.IHuaweiPaymentService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.util.Assert;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
/**
* @author zoukun
*/
@Slf4j
@RestController
@RequestMapping("/payment")
public class HuaweiPaymentController {
@Autowired
private IHuaweiPaymentService huaweiPaymentService;
/**
* 华为支付回调地址
*/
@RequestMapping("/callback/huawei")
public AjaxResult callback(@RequestBody HuaweiPaymentCallback callback) {
log.info("进入callback params" + JSONObject.toJSONString(callback));
AjaxResult ajax = AjaxResult.success();
return ajax;
}
/**
* 华为购买验证(订购会员)
*/
@PostMapping("/huawei/purchases/verify")
public AjaxResult purchasesVerify(@Validated @RequestBody HuaweiPurchasesVerifyDTO verifyDTO) {
log.info("进入/huawei/purchases/tokens/verify params" + JSONObject.toJSONString(verifyDTO));
huaweiPaymentService.purchasesVerify(verifyDTO);
return AjaxResult.success();
}
}

View File

@ -0,0 +1,35 @@
package com.sf.payment.domain;
import lombok.*;
import java.io.Serializable;
/**
* 授权回调时的参数类
*
* @author zk
*/
@Getter
@Setter
@Builder
@AllArgsConstructor
@NoArgsConstructor
public class HuaweiPaymentCallback implements Serializable {
/**
* 访问AuthorizeUrl后回调时带的参数code
*/
private String code;
/**
* 客户端id对应各平台的appKey
*/
private String clientId;
/**
* 客户端Secret对应各平台的appSecret
*/
private String clientSecret;
}

View File

@ -0,0 +1,53 @@
package com.sf.payment.domain;
import apijson.NotNull;
import lombok.*;
import javax.validation.constraints.NotBlank;
import java.io.Serializable;
/**
* 华为验证购买tokenDTO
*
* @author zk
*/
@Getter
@Setter
@Builder
@AllArgsConstructor
@NoArgsConstructor
public class HuaweiPurchasesVerifyDTO implements Serializable {
/**
* 商品类型
* 0消耗型商品
* 1非消耗型商品
* 2自动续期订阅商品
*/
@NotNull
private Integer type;
/**
* 包含订单信息的JWS格式数据
* 可参见对返回结果验签
* 解码验签获取相关购买数据的JSON字符串
* 其包含的参数请参见PurchaseOrderPayload
*/
private String jwsPurchaseOrder;
/**
* 包含订阅状态信息的
* JWS格式数据
* 可参见对返回结果验签
* 解码验签获取相关订阅状态
* 信息的JSON字符串
* 其包含的参数请参见
* SubGroupStatusPayload
*/
private String jwsSubscriptionStatus;
}

View File

@ -0,0 +1,56 @@
package com.sf.payment.domain;
import apijson.NotNull;
import lombok.*;
import javax.validation.constraints.NotBlank;
import java.io.Serializable;
/**
* 华为验证购买tokenD返回
*
* @author zk
*/
@Getter
@Setter
@Builder
@AllArgsConstructor
@NoArgsConstructor
public class HuaweiPurchasesVerifyResponseDTO implements Serializable {
/**
* 返回码
*
* 0成功
* 其他失败具体请参见错误码
*/
private String responseCode;
/**
* 响应描述
*/
private String responseMessage;
/**
*
* 包含购买数据的JSON字符串具体请参见表InappPurchaseDetails
*
* 该字段原样参与签名
*/
private String purchaseTokenData;
/**
* purchaseTokenData基于应用RSA IAP私钥的签名信息签名算法为signatureAlgorithm
* 应用请参见对返回结果验签使用IAP公钥对PurchaseTokenData的JSON字符串进行验签
*/
private String dataSignature;
/**
*
* 签名算法
*/
@NotBlank(message = "待下发商品ID不能为空")
private String signatureAlgorithm;
}

View File

@ -0,0 +1,35 @@
package com.sf.payment.domain;
import lombok.Data;
/**
* 功能描述:
*
* @author a_kun
* @date 2024/4/17 14:41
*/
@Data
public class HuaweiQueryResponse {
/**
* 返回码
* 0成功
* 其他失败具体请参见错误码
*/
private String responseCode;
/**
* 响应描述
*/
private String responseMessage;
/**
* 包含已购订单相关状态信息的JWS格式数据可参见对返回结果验签解码验签获取相关订单状态信息的JSON字符串其包含的参数具体请参见表PurchaseOrderPayload说明
*/
private String jwsPurchaseOrder;
/**
* 包含已购订阅相关状态信息的JWS格式数据可参见对返回结果验签解码验签获取相关订阅状态信息的JSON字符串其包含的参数请参见SubGroupStatusPayload
*/
private String jwsSubGroupStatus;
}

View File

@ -0,0 +1,233 @@
package com.sf.payment.domain;
import lombok.Data;
/**
* 功能描述:
*
* @author a_kun
* @date 2024/4/16 15:29
*/
@Data
public class InAppPurchaseData {
/**
* 应用ID
*/
private Long applicationId;
/**
* 消耗型商品或者非消耗型商品固定为false
*
* 订阅型商品
*
* true订阅处于活动状态并且将在下一个结算日期自动续订
* false用户已经取消订阅 用户可以在下一个结算日期之前访问订阅内容并且在该日期后将无法访问除非重新启用自动续订 如果提供了宽限期只要宽限期未过此值就会对所有订阅保持设置为true 下一次结算日期每天都会自动延长直至宽限期结束或者用户更改付款方式
*/
private Boolean autoRenewing;
/**
* 订单ID唯一标识一笔需要收费的收据由华为应用内支付服务器在创建订单以及订阅型商品续费时生成
*
* 每一笔新的收据都会使用不同的orderId
*/
private String orderId;
/**
* 商品类别取值包括
*
* 0消耗型商品
* 1非消耗型商品
* 2订阅型商品
*/
private Integer kind;
/**
* 商品ID每种商品必须有唯一的ID由应用在PMS中维护或者应用发起购买时传入
* 说明
* 为避免资金损失您在对支付结果验签成功后必须对其进行校验
*/
private String productId;
/**
* 商品名称
*/
private String productName;
/**
* 商品购买时间UTC时间戳以毫秒为单位
*/
private Long purchaseTime;
/**
* 订单交易状态
*
* -1初始化
* 0已购买
* 1已取消
* 2已撤销或已退款
* 3待处理
*/
private Integer purchaseState;
/**
*
* 商户侧保留信息由您在调用支付接口时传入
*/
private String developerPayload;
/**
*消耗状态仅一次性商品存在取值包括
*
* 0未消耗
* 1已消耗
*/
private Integer consumptionState;
/**
*确认状态取值包括
*
* 0 未确认
* 1已确认
* 没有值表示不需要确认
*/
private Integer confirmed;
/**
* 用于唯一标识商品和用户对应关系的购买令牌在支付完成时由华为应用内支付服务器生成
* 说明
* 该字段是唯一标识商品和用户对应关系的在订阅型商品正常续订时不会改变
* 当前92位后续存在扩展可能如要进行存储建议您预留128位的长度
* 如要进行存储为保证安全建议加密存储
*/
private String purchaseToken;
/**
* 用定价货币的币种请参见ISO 4217标准
* 说明
* 为避免资金损失您在对支付结果验签成功后必须对其进行校验
*/
private String currency;
/**
* 商品实际价格*100以后的值商品实际价格精确到小数点后2位例如此参数值为501则表示商品实际价格为5.01
*/
private Long price;
/**
* 支付方式取值请参见payType说明
*/
private String payType;
/**
* 交易单号用户支付成功后生成
*/
private String payOrderId;
// 以下参数只在订阅场景返回
/**
* 上次续期收款的订单ID由支付服务器在续期扣费时生成首次购买订阅型商品时的lastOrderId与orderId数值相同
*/
private String lastOrderId;
/**
* 订阅型商品所属的订阅组ID
*/
private String productGroup;
/**
* 原购买的时间即本订阅型商品首次成功收费的时间UTC时间戳以毫秒为单位
*/
private Long oriPurchaseTime;
/**
* 订阅ID
* 说明
* subscriptionId是用户与商品之间的一一对应关系在订阅型商品正常续订时不会改变
*/
private String subscriptionId;
/**
* 原订阅ID有值表示当前订阅是从其他商品切换来的该值可以关联切换前的商品订阅信息
*/
private String oriSubscriptionId;
/**
* 购买数量
*/
private Integer quantity;
/**
* 已经付费订阅的天数免费试用和促销期周期除外
*/
private Long daysLasted;
/**
* 成功标准续期没有设置促销的续期的期数为0或者不存在表示还没有成功续期
*/
private Long numOfPeriods;
/**
* 成功促销续期期数
*/
private Long numOfDiscount;
/**
* 订阅型商品过期时间UTC时间戳以毫秒为单位
*
* 对于一个成功收费的自动续订收据该时间表示续期日期或者超期日期如果商品最近的收据的该时间是一个过去的时间则订阅已经过期
*/
private Long expirationDate;
/**
* 对于已经过期的订阅表示过期原因取值包括
*
* 1用户取消
* 2商品不可用
* 3用户签约信息异常
* 4Billing错误
* 5用户未同意涨价
* 6未知错误
* 同时有多个异常时优先级为1 > 2 > 3
*/
private Integer expirationIntent;
/**
* 订阅撤销时间UTC时间戳以毫秒为单位发生退款且服务立即不可用在顾客投诉通过客服撤销订阅或者顾客升级跨级到同组其他商品并且立即生效场景下需要撤销原有订阅的上次收据时有值
* 说明
* 已经撤销的收据等同于没有完成购买
*/
private Long cancelTime;
/**
* 取消原因
*
* 3: 应用调用IAP接口取消
* 2顾客升级跨级等
* 1顾客因为在App内遇到了问题而取消了订阅
* 0其他原因取消比如顾客错误地订阅了商品
* 说明
* 如果为空且cancelTime有值表示是升级等操作导致的取消
*/
private Integer cancelReason;
/**
* 续期状态
*
* 1当前周期到期时自动续期
* 0用户停止了续期
* 仅针对自动续期订阅对有效和过期的订阅均有效并不代表顾客的订阅状态通常取值为0时应用可以给顾客提供其他的订阅选项
* 例如推荐一个同组更低级别的商品该值为0通常代表着顾客主动取消了该订阅
*/
private Integer renewStatus;
/**
* 用户取消订阅的时间UTC时间戳以毫秒为单位在该时间进行了订阅续期停止的设定商品在有效期内仍然有效但后续的续期会终止无退款
*/
private Integer cancellationTime;
}

View File

@ -0,0 +1,165 @@
package com.sf.payment.domain;
import lombok.Data;
/**
* 功能描述:
* 订单信息模型支持消耗型商品非消耗型商品和自动续期订阅商品
* @author a_kun
* @date 2024/4/16 15:29
*/
@Data
public class PurchaseOrderPayload {
/**
* 具体一笔订单中对应的购买订单号ID
*/
private String purchaseOrderId;
/**
* 购买token
* 在购买消耗型/非消耗型商品场景中与具体购买订单一一对应
* 在自动续期订阅商品场景中与订阅ID一一对应
*/
private String purchaseToken;
/**
* 应用ID
*/
private String applicationId;
/**
* 商品ID每种商品必须有唯一的ID由应用在PMS中维护或者应用发起购买时传入
* 说明
* 为避免资金损失您在对支付结果验签成功后必须对其进行校验
*/
private String productId;
/**
* 商品类型具体取值如下
* 0消耗型商品
* 1非消耗型商品
* 2自动续期订阅商品
*/
private Integer productType;
/**
* 购买时间UTC时间戳以毫秒为单位
* 如果没有完成购买则没有值
*/
private Long purchaseTime;
/**
* 发货状态具体取值如下
* 1已发货
* 2未发货
*/
private Integer finishStatus;
/**
* 价格单位
* 实际价格*100以后的值商品实际价格精确到小数点后2位例如此参数值为501则表示商品实际价格为5.01
*/
private Long price;
/**
* 用定价货币的币种请参见ISO 4217标准
* 说明
* 为避免资金损失您在对支付结果验签成功后必须对其进行校验
*/
private String currency;
/**
* 商户侧保留信息由您在调用支付接口时传入
*/
private String developerPayload;
/**
* 购买订单撤销原因
* 0其他
* 1用户遇到问题退款
*/
private Integer purchaseOrderRevocationReasonCode;
/**
* 购买订单撤销时间
* UTC时间戳以毫秒为单位
*/
private Long revocationTime;
/**
* 优惠类型
* 1推介促销
*/
private Integer offerTypeCode;
/**
* 优惠ID
*/
private String offerId;
/**
* 国家/地区码用于区分国家/地区信息请参见ISO 3166
*/
private String countryCode;
/**
* 签名时间UTC时间戳以毫秒为单位
*/
private Long signedTime;
// 以下参数只在自动续期订阅商品场景返回
/**
* 订阅连续购买段的唯一ID
* 当用户切换商品不会重置此ID
*/
private String subGroupGenerationId;
/**
* 订阅连续购买段的唯一ID
* 当用户切换订阅商品时
* 此订阅ID会发生改变
*/
private String subscriptionId;
/**
* 订阅组ID
*/
private String subGroupId;
/**
* 此次购买的有效周期
* 采用ISO 8601格式
* 例如P1W表示一周
* P1M表示一个月
*/
private String duration;
/**
* 订阅周期段类型
* 0正常周期段
* 1延期周期段
*/
private Integer durationTypeCode;
/*
ISO 8601的时间持续期限表示
在ISO 8601中时间持续期限的表示采用了一种简洁而明确的格式例如 P10D其中 P 表示周期Period后面的数字表示周期的长度而末尾的字母表示周期的单位这种表示法主要用于描述时间段的长度而不关注具体的时刻
P 表示周期Period 此字母指示接下来的时间表示将是一个时间段的描述而非具体的日期或时刻
后面的数字 这个数字表示时间段的长度可以是整数或小数它指示了在时间单位内的周期数量
末尾的字母表示周期的单位 P10D 末尾的 D 表示周期的单位是天DaysISO 8601定义了多种可能的时间单位包括
Y 表示年份例如 P2Y 表示2年的时间段
M 表示月份例如 P3M 表示3个月的时间段
W 表示周数例如 P1W 表示1周的时间段
D 表示天数例如 P10D 表示10天的时间段
T时间分隔符 如果时间段中包含了时间信息日期和时间之间用 T 分隔例如 P1DT12H 表示1天12小时的时间段
H小时M分钟S 用于表示时秒的时间段长度例如 PT2H30M 表示2小时30分钟的时间段
示例
P1Y 表示1年的时间段
P3M 表示3个月的时间段
P2W 表示2周的时间段
P4DT6H30M 表示4天6小时30分钟的时间段
*/
}

View File

@ -0,0 +1,48 @@
package com.sf.payment.domain;
import lombok.Data;
import java.util.List;
/**
* 功能描述:
* 已购订阅相关状态信息
* @author a_kun
* @date 2024/4/16 15:29
*/
@Data
public class SubGroupStatusPayload {
/**
* 应用ID
*/
private String applicationId;
/**
* 应用包名
*/
private String packageName;
/**
* 订阅组ID
*/
private String subGroupId;
/**
* 订阅组中最后生效的
* 订阅状态
* SubscriptionStatus
* 比如A切换BB切换C
* 此处是C的订阅状态
*/
private SubscriptionStatus lastSubscriptionStatus;
/**
* 订阅组最近生效的
* 历史订阅状态
* SubscriptionStatus的列表比如A切换BB切换C这里包含CBA三个订阅状态信息
*/
private List<SubscriptionStatus> historySubscriptionStatusList;
}

View File

@ -0,0 +1,91 @@
package com.sf.payment.domain;
import lombok.Data;
import java.util.List;
/**
* 功能描述:
* 当前订阅最新的未来扣费计划
* @author a_kun
* @date 2024/4/16 15:29
*/
@Data
public class SubRenewalInfo {
/**
* 订阅连续购买段的唯一ID
* 当用户切换商品不会重置此ID
*/
private String subGroupGenerationId;
/**
* 下周期生效场景下下期将续期的商品ID
*/
private String nextRenewPeriodProductId;
/**
* 当前生效的商品ID
*/
private String productId;
/**
* 自动续期状态
* 0关闭
* 1打开
*/
private Integer autoRenewStatusCode;
/**
* 系统是否还在尝试扣费
* true
* false
*/
private Boolean hasInBillingRetryPeriod;
/**
* 目前涨价状态码
* 1用户暂未同意涨价
* 2用户已同意涨价
*/
private Integer priceIncreaseStatusCode;
/**
* 优惠类型
* 1推介促销
*/
private Integer offerTypeCode;
/**
* 优惠ID
*/
private String offerId;
/**
* 下期续费价格单位取消订阅场景下不返回
*/
private String renewalPrice;
/**
* 币种
*/
private String currency;
/**
* 续期时间UTC时间戳以毫秒为单位
*/
private Long renewalTime;
/**
* 订阅续期失败的原因
* 1用户取消
* 2商品无效
* 3签约无效
* 4扣费异常
* 5用户不同意涨价
* 6未知
*/
private String expirationIntent;
}

View File

@ -0,0 +1,68 @@
package com.sf.payment.domain;
import lombok.Data;
import java.util.List;
/**
* 功能描述:
* 订阅组中最后生效的订阅状态
* @author a_kun
* @date 2024/4/16 15:29
*/
@Data
public class SubscriptionStatus {
/**
* 订阅连续购买段的唯一ID
* 当用户切换商品不会重置此ID
*/
private String subGroupGenerationId;
/**
* 订阅连续购买段的唯一ID
* 当用户切换订阅商品时
* 此订阅ID会发生改变
*/
private String subscriptionId;
/**
* 购买token
* 在购买消耗型/非消耗型商品场景中与具体购买订单一一对应
* 在自动续期订阅商品场景中与订阅ID一一对应
*/
private String purchaseToken;
/**
* 订阅状态
* 1生效状态
* 2已到期
* 3尝试扣费
* 5撤销
* 6暂停
*/
private Integer status;
/**
* 自动续期订阅商品的过期时间UTC时间戳以毫秒为单位
*/
private Long expiresTime;
/**
* 当前订阅最新的一笔购买订单包含的参数请参见PurchaseOrderPayload
*/
private PurchaseOrderPayload lastPurchaseOrder;
/**
* 当前订阅最新的购买订单列表包含续期延期折算等产生的购买订单
* 购买订单包含的参数请参见PurchaseOrderPayload
*/
private List<PurchaseOrderPayload> recentPurchaseOrderList;
/**
* 当前订阅最新的未来扣费计划包含的参数请参见SubRenewalInfo
*/
private SubRenewalInfo renewalInfo;
}

View File

@ -0,0 +1,14 @@
package com.sf.payment.service;
import com.sf.payment.domain.HuaweiPurchasesVerifyDTO;
/**
* 功能描述:
*
* @author a_kun
* @date 2024/4/12 10:21
*/
public interface IHuaweiPaymentService {
void purchasesVerify(HuaweiPurchasesVerifyDTO verifyDTO);
}

View File

@ -0,0 +1,403 @@
package com.sf.payment.service.impl;
import cn.hutool.core.date.DateField;
import cn.hutool.core.date.DateTime;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.http.HttpUtil;
import com.alibaba.fastjson2.JSON;
import com.auth0.jwt.JWT;
import com.auth0.jwt.interfaces.DecodedJWT;
import com.sf.common.enums.RequestHeaderEnums;
import com.sf.common.utils.DateUtils;
import com.sf.common.utils.SecurityUtils;
import com.sf.common.utils.SnowflakeIdWorker;
import com.sf.common.utils.http.RequestUtils;
import com.sf.order.domain.OrderInfo;
import com.sf.order.service.IOrderInfoService;
import com.sf.payment.config.HuaweiPaymentConfig;
import com.sf.payment.constant.GoodsConstants;
import com.sf.payment.domain.*;
import com.sf.payment.service.IHuaweiPaymentService;
import com.sf.payment.utils.HuaweiTokenGenerator;
import com.sf.service.domain.GoodsMessages;
import com.sf.service.service.IGoodsMessagesService;
import com.sf.system.domain.UserMember;
import com.sf.system.service.IUserMemberService;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.codec.binary.Base64;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.Assert;
import org.springframework.util.Base64Utils;
import javax.annotation.Resource;
import java.nio.charset.StandardCharsets;
import java.security.KeyFactory;
import java.security.MessageDigest;
import java.security.PublicKey;
import java.security.Security;
import java.security.spec.X509EncodedKeySpec;
import java.text.MessageFormat;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
/**
* 功能描述:
*
* @author a_kun
* @date 2024/4/12 10:21
*/
@Slf4j
@Service
public class HuaweiPaymentServiceImpl implements IHuaweiPaymentService {
/**
* token url to get the authorization
*/
private static final String TOKEN_URL = "https://oauth-login.cloud.huawei.com/oauth2/v3/token";
/**
* 查询消耗型/非消耗型商品的订单最新状态
*/
private static final String ORDER_STATUS_QUERY_URL = "/order/harmony/v1/application/order/status/query";
/**
* 查询自动续期订阅商品的最新状态
*/
private static final String SUBSCRIPTION_STATUS_QUERY_URL = "/subscription/harmony/v1/application/subscription/status/query";
/**
* 站点信息(中国)
*/
private static final String ROOT_URL = "https://iap.cloud.huawei.com";
private static final String PUBLIC_KEY = "PUBLIC_KEY";
@Resource
private IOrderInfoService orderInfoService;
@Resource
private IUserMemberService userMemberService;
@Resource
private IGoodsMessagesService goodsMessagesService;
@Resource
private HuaweiPaymentConfig huaweiPaymentConfig;
@Resource
private SnowflakeIdWorker snowflakeIdWorker;
@Override
@Transactional(rollbackFor = Exception.class)
public void purchasesVerify(HuaweiPurchasesVerifyDTO verifyDTO) {
// 验证 TODO 证书验签官网未实现
if (GoodsConstants.GOODS_TYPE_CONSUMABLE.equals(verifyDTO.getType())
|| GoodsConstants.GOODS_TYPE_NON_CONSUMABLE.equals(verifyDTO.getType())) {
Assert.hasText(verifyDTO.getJwsPurchaseOrder(), "订单信息不能为空");
// 消耗/非消耗商品购买验证
consumablePurchasesVerify(verifyDTO.getJwsPurchaseOrder());
} else if (GoodsConstants.GOODS_TYPE_AUTOMATIC_RENEWAL_SUBSCRIPTION.equals(verifyDTO.getType())) {
Assert.hasText(verifyDTO.getJwsSubscriptionStatus(), "订单信息不能为空");
// 订阅商品购买验证
subscriptionPurchasesVerify(verifyDTO.getJwsSubscriptionStatus());
} else {
throw new IllegalArgumentException("商品类型错误!");
}
}
private PurchaseOrderPayload subscriptionPurchasesVerify(String jwsSubscriptionStatus) {
DecodedJWT decodedJWT = JWT.decode(jwsSubscriptionStatus);
//String header = decodedJWT.getHeader();
String payload = decodedJWT.getPayload();
// 前面应该不是base64编码后的官网说都是编码后的但是解码会报错
//String signature = decodedJWT.getSignature();
String decodeAppPayload = new String(Base64Utils.decode(payload.getBytes(StandardCharsets.UTF_8)), StandardCharsets.UTF_8);
// String decodeHeader = new String(Base64Utils.decode(header.getBytes(StandardCharsets.UTF_8)), StandardCharsets.UTF_8);
// String decodeSignature = new String(Base64Utils.decode(signature.getBytes(StandardCharsets.UTF_8)), StandardCharsets.UTF_8);
SubGroupStatusPayload appSubGroupStatusPayload = JSON.parseObject(decodeAppPayload, SubGroupStatusPayload.class);
SubscriptionStatus lastSubscriptionStatus = appSubGroupStatusPayload.getLastSubscriptionStatus();
PurchaseOrderPayload lastPurchaseOrder = lastSubscriptionStatus.getLastPurchaseOrder();
// pack the request body
Map<String, String> bodyMap = new HashMap<>();
bodyMap.put("purchaseToken", lastPurchaseOrder.getPurchaseToken());
bodyMap.put("purchaseOrderId", lastPurchaseOrder.getPurchaseOrderId());
// construct the Authorization in Header
Map<String, String> headers = buildAuthorization(huaweiPaymentConfig.getAppId(), bodyMap);
log.info("调用华为主动续期入惨:{}", JSON.toJSONString(bodyMap));
// 订阅状态查询
String response = HttpUtil.createPost(ROOT_URL + SUBSCRIPTION_STATUS_QUERY_URL)
.addHeaders(headers)
.body(JSON.toJSONString(bodyMap))
.execute().body();
log.info("订单状态查询返回信息:{}", response);
HuaweiQueryResponse huaweiQueryResponse = JSON.parseObject(response, HuaweiQueryResponse.class);
if (!"0".equals(huaweiQueryResponse.getResponseCode())) {
throw new RuntimeException("订单状态查询失败");
}
DecodedJWT huaweiQueryResponseDecodedJWT = JWT.decode(huaweiQueryResponse.getJwsSubGroupStatus());
String huaweiQueryResponsepayload = huaweiQueryResponseDecodedJWT.getPayload();
String decodeHuaweiQueryResponsepayload = new String(Base64Utils.decode(huaweiQueryResponsepayload.getBytes(StandardCharsets.UTF_8)), StandardCharsets.UTF_8);
SubGroupStatusPayload subGroupStatusPayload = JSON.parseObject(decodeHuaweiQueryResponsepayload, SubGroupStatusPayload.class);
PurchaseOrderPayload huaweiQueryResponsePurchaseOrderPayload = subGroupStatusPayload.getLastSubscriptionStatus().getLastPurchaseOrder();
// 发货
return delivery(lastPurchaseOrder, huaweiQueryResponsePurchaseOrderPayload, subGroupStatusPayload.getLastSubscriptionStatus());
}
/**
* 发货
*
* @param purchaseOrder
* @param huaweiQueryResponsePurchaseOrderPayload
* @param lastSubscriptionStatus
* @return
*/
private PurchaseOrderPayload delivery(PurchaseOrderPayload purchaseOrder, PurchaseOrderPayload huaweiQueryResponsePurchaseOrderPayload, SubscriptionStatus lastSubscriptionStatus) {
Assert.isTrue(purchaseOrder.getPurchaseOrderId().equals(huaweiQueryResponsePurchaseOrderPayload.getPurchaseOrderId()), "订单不一致,发货失败!");
if (2 == huaweiQueryResponsePurchaseOrderPayload.getFinishStatus()) {
// 还未发货
// 查询平台是否配置该商品
GoodsMessages goods = goodsMessagesService.selectGoodsMessagesByCode(huaweiQueryResponsePurchaseOrderPayload.getProductId());
Assert.notNull(goods, "未配置此商品,请检查商品配置");
Assert.isTrue(goods.getOriginalPrice().equals(huaweiQueryResponsePurchaseOrderPayload.getPrice()), "商品价格与订单价格不一致,请检查价格配置");
// 创建完成订单
createOrder(huaweiQueryResponsePurchaseOrderPayload, goods);
// 发放会员权益
distributeMembershipBenefits(huaweiQueryResponsePurchaseOrderPayload, lastSubscriptionStatus);
} else {
log.info("华为应用内支付订单已发货!{}", JSON.toJSONString(huaweiQueryResponsePurchaseOrderPayload));
}
return huaweiQueryResponsePurchaseOrderPayload;
}
private PurchaseOrderPayload consumablePurchasesVerify(String jwsPurchaseOrder) {
DecodedJWT decodedJWT = JWT.decode(jwsPurchaseOrder);
//String header = decodedJWT.getHeader();
String payload = decodedJWT.getPayload();
// 前面应该不是base64编码后的官网说都是编码后的但是解码会报错
//String signature = decodedJWT.getSignature();
String decodeAppPayload = new String(Base64Utils.decode(payload.getBytes(StandardCharsets.UTF_8)), StandardCharsets.UTF_8);
// String decodeHeader = new String(Base64Utils.decode(header.getBytes(StandardCharsets.UTF_8)), StandardCharsets.UTF_8);
// String decodeSignature = new String(Base64Utils.decode(signature.getBytes(StandardCharsets.UTF_8)), StandardCharsets.UTF_8);
PurchaseOrderPayload appPurchaseOrderPayload = JSON.parseObject(decodeAppPayload, PurchaseOrderPayload.class);
// pack the request body
Map<String, String> bodyMap = new HashMap<>();
bodyMap.put("purchaseToken", appPurchaseOrderPayload.getPurchaseToken());
bodyMap.put("purchaseOrderId", appPurchaseOrderPayload.getPurchaseOrderId());
// construct the Authorization in Header
Map<String, String> headers = buildAuthorization(huaweiPaymentConfig.getAppId(), bodyMap);
// 订单状态查询
String response = HttpUtil.createPost(ROOT_URL + ORDER_STATUS_QUERY_URL)
.addHeaders(headers)
.body(JSON.toJSONString(bodyMap))
.execute().body();
log.info("订单状态查询返回信息:{}", response);
HuaweiQueryResponse huaweiQueryResponse = JSON.parseObject(response, HuaweiQueryResponse.class);
if (!"0".equals(huaweiQueryResponse.getResponseCode())) {
throw new RuntimeException("订单状态查询失败");
}
DecodedJWT huaweiQueryResponseDecodedJWT = JWT.decode(huaweiQueryResponse.getJwsPurchaseOrder());
// String huaweiQueryResponseHeader = huaweiQueryResponseDecodedJWT.getHeader();
String huaweiQueryResponsepayload = huaweiQueryResponseDecodedJWT.getPayload();
// String huaweiQueryResponsesignature = huaweiQueryResponseDecodedJWT.getSignature();
//String decodehuaweiQueryResponseHeader = new String(Base64Utils.decode(huaweiQueryResponseHeader.getBytes(StandardCharsets.UTF_8)), StandardCharsets.UTF_8);
String decodehuaweiQueryResponsepayload = new String(Base64Utils.decode(huaweiQueryResponsepayload.getBytes(StandardCharsets.UTF_8)), StandardCharsets.UTF_8);
// String decodehuaweiQueryResponsesignature = new String(Base64Utils.decode(huaweiQueryResponsesignature.getBytes(StandardCharsets.UTF_8)), StandardCharsets.UTF_8);
PurchaseOrderPayload huaweiQueryResponsePurchaseOrderPayload = JSON.parseObject(decodehuaweiQueryResponsepayload, PurchaseOrderPayload.class);
// 暂时只做简单验证
return delivery(appPurchaseOrderPayload, huaweiQueryResponsePurchaseOrderPayload, null);
}
private void createOrder(PurchaseOrderPayload appPurchaseOrderPayload, GoodsMessages goods) {
Long userId = SecurityUtils.getUserId();
OrderInfo orderInfo = new OrderInfo();
orderInfo.setAppCode(RequestUtils.getHeader(RequestHeaderEnums.APP_CODE.getCode()));
orderInfo.setOrderNo(snowflakeIdWorker.nextId());
orderInfo.setOrderStatus(4L);
orderInfo.setPayType(1L);
orderInfo.setPayChannel(2L);
orderInfo.setOrderAmt(appPurchaseOrderPayload.getPrice());
orderInfo.setPayAmt(appPurchaseOrderPayload.getPrice());
orderInfo.setReallyAmt(appPurchaseOrderPayload.getPrice());
orderInfo.setReceiveType(0L);
orderInfo.setGoodsId(goods.getId());
orderInfo.setPayTime(DateUtil.date(appPurchaseOrderPayload.getPurchaseTime()));
orderInfo.setCreateUserId(userId);
orderInfo.setUpdateUserId(userId);
orderInfo.setOutOrderNo(appPurchaseOrderPayload.getPurchaseOrderId());
orderInfo.setPayData(JSON.toJSONString(appPurchaseOrderPayload));
orderInfo.setGoodsPrice(goods.getOriginalPrice());
orderInfo.setGoodsType(goods.getGoodsType());
orderInfo.setGoodsCode(goods.getGoodsCode());
orderInfo.setCreateTime(DateUtils.getNowDate());
orderInfo.setUpdateTime(DateUtils.getNowDate());
orderInfoService.insertOrder(orderInfo);
}
private void distributeMembershipBenefits(PurchaseOrderPayload purchaseOrderPayload, SubscriptionStatus lastSubscriptionStatus) {
// 发放会员权益
Long userId = SecurityUtils.getUserId();
UserMember userMember = userMemberService.selectUserMemberByUserId(userId);
boolean isSubscription = GoodsConstants.GOODS_TYPE_AUTOMATIC_RENEWAL_SUBSCRIPTION.equals(purchaseOrderPayload.getProductType());
int subscriptionStatus = isSubscription ? lastSubscriptionStatus.getStatus() : 0;
if (userMember == null) {
// 添加会员信息
DateTime payTime = DateUtil.date(purchaseOrderPayload.getPurchaseTime());
userMember = new UserMember();
userMember.setMemberLevel(isSubscription ? 1 : 2);
userMember.setSubscriptionStatus(subscriptionStatus);
userMember.setUserId(userId);
userMember.setIntegration(0L);
DateTime expirationTime = DateUtil.offset(payTime, DateField.MONTH, 1);
userMember.setExpirationTime(expirationTime);
userMember.setCreateTime(new Date());
userMember.setUpdateTime(new Date());
userMemberService.insertUserMember(userMember);
} else {
// 更新
userMember.setMemberLevel(isSubscription ? 1 : 2);
userMember.setSubscriptionStatus(subscriptionStatus);
DateTime expirationTime = DateUtil.offset(userMember.getExpirationTime(), DateField.MONTH, 1);
userMember.setExpirationTime(expirationTime);
userMember.setUpdateTime(new Date());
userMemberService.updateUserMember(userMember);
}
}
/**
* Build Authorization in Header
*
* @return headers
*/
public static Map<String, String> buildAuthorization(String appId, Map<String, String> body) {
Map<String, Object> jwtHeader = new HashMap<>(8);
jwtHeader.put("alg", "ES256");
jwtHeader.put("typ", "JWT");
jwtHeader.put("kid", "0ae3e1be-374b-43a5-a297-045addbf76eb");
Map<String, Object> jwtPayload = new HashMap<>(8);
jwtPayload.put("iss", "f59509e6-dd17-4644-b832-ff05233146c8");
jwtPayload.put("aud", "iap-v1");
jwtPayload.put("iat", DateUtil.currentSeconds());
jwtPayload.put("exp", DateUtil.currentSeconds() + 1800L); // 半小时过期
jwtPayload.put("aid", appId);
jwtPayload.put("digest", getJwtPayloadDigest(body));
String token = HuaweiTokenGenerator.createToken(jwtHeader, jwtPayload);
// String authorization = MessageFormat.format("Basic {0}", Base64.encodeBase64String(oriString.getBytes(StandardCharsets.UTF_8)));
String authorization = MessageFormat.format("Bearer {0}", token);
Map<String, String> headers = new HashMap<>();
headers.put("Authorization", authorization);
headers.put("Content-Type", "application/json; charset=UTF-8");
return headers;
}
private static String getJwtPayloadDigest(Map<String, String> body) {
try {
MessageDigest messageDigest = MessageDigest.getInstance("SHA-256");
messageDigest.update(JSON.toJSONString(body).getBytes(StandardCharsets.UTF_8));
byte[] digestByte = messageDigest.digest();
StringBuilder stringBuffer = new StringBuilder();
String temp;
for (byte aByte : digestByte) {
temp = Integer.toHexString(aByte & 0xFF);
if (temp.length() == 1) {
stringBuffer.append("0");
}
stringBuffer.append(temp);
}
return stringBuffer.toString();
} catch (Exception e) {
throw new RuntimeException(e);
}
}
/**
* 校验签名信息校验InAppPurchaseData中的productIdpricecurrency等信息的一致性
*
* @param content 结果字符串
* @param sign 签名字符串
* @param publicKey IAP公钥
* @return 是否校验通过
*/
public static boolean checkSuccessOrder(String content, String sign, String publicKey, String signatureAlgorithm, OrderInfo orderInfo) {
// 校验签名信息
boolean checkRes = checkSign(content, sign, publicKey, StrUtil.blankToDefault(signatureAlgorithm, "SHA256WithRSA"));
if (checkRes) {
// 校验InAppPurchaseData中的productIdpricecurrency等信息的一致性
checkRes = checkProductIdAndPriceAndCurrency(content, orderInfo);
}
return checkRes;
}
/**
* 校验InAppPurchaseData中的productIdpricecurrency等信息的一致性
*
* @param content 结果字符串
* @param orderInfo 您的订单信息包括productIdpricecurrency
* @return 是否校验通过
*/
public static boolean checkProductIdAndPriceAndCurrency(String content, OrderInfo orderInfo) {
InAppPurchaseData inAppPurchaseData = JSON.parseObject(content, InAppPurchaseData.class);
// 校验InAppPurchaseData中的productIdpricecurrency等信息的一致性
return inAppPurchaseData.getProductId().equals(orderInfo.getGoodsId())
&& inAppPurchaseData.getPrice().equals(orderInfo.getOrderAmt());
}
/**
* 校验签名信息
*
* @param content 结果字符串
* @param sign 签名字符串
* @param publicKey IAP公钥
* @param signatureAlgorithm 签名算法字段可从接口返回数据中获取例如OwnedPurchasesResult.getSignatureAlgorithm()
* @return 是否校验通过
*/
public static boolean checkSign(String content, String sign, String publicKey, String signatureAlgorithm) {
if (sign == null) {
return false;
}
if (publicKey == null) {
return false;
}
// 当signatureAlgorithm为空时使用默认签名算法
if (signatureAlgorithm == null || signatureAlgorithm.length() == 0) {
signatureAlgorithm = "SHA256WithRSA";
System.out.println("doCheck, algorithm: SHA256WithRSA");
}
try {
Security.addProvider(new org.bouncycastle.jce.provider.BouncyCastleProvider());
// 生成"RSA"的KeyFactory对象
KeyFactory keyFactory = KeyFactory.getInstance("RSA");
byte[] decodedKey = Base64.decodeBase64(publicKey);
// 生成公钥
PublicKey pubKey = keyFactory.generatePublic(new X509EncodedKeySpec(decodedKey));
java.security.Signature signature = null;
// 根据SHA256WithRSA算法获取签名对象实例
signature = java.security.Signature.getInstance(signatureAlgorithm);
// 初始化验证签名的公钥
signature.initVerify(pubKey);
// 把原始报文更新到签名对象中
signature.update(content.getBytes(StandardCharsets.UTF_8));
// 将sign解码
byte[] bsign = Base64.decodeBase64(sign);
// 进行验签
return signature.verify(bsign);
} catch (RuntimeException e) {
throw e;
} catch (Exception e) {
e.printStackTrace();
}
return false;
}
}

View File

@ -0,0 +1,43 @@
package com.sf.payment.utils;
import cn.hutool.core.io.resource.ClassPathResource;
import com.auth0.jwt.JWT;
import com.auth0.jwt.algorithms.Algorithm;
import org.apache.commons.io.IOUtils;
import java.io.IOException;
import java.io.InputStream;
import java.nio.charset.StandardCharsets;
import java.security.KeyFactory;
import java.security.NoSuchAlgorithmException;
import java.security.interfaces.ECPrivateKey;
import java.security.spec.InvalidKeySpecException;
import java.security.spec.PKCS8EncodedKeySpec;
import java.util.Base64;
import java.util.Map;
public class HuaweiTokenGenerator {
public static String createToken(Map<String, Object> jwtHeader, Map<String, Object> jwtPayload) {
try {
// AppGallery Connect 华为应用内支付配置密钥下载私钥文件
ClassPathResource classPathResource = new ClassPathResource("IAPKey_0ae3e1be-374b-43a5-a297-045addbf76eb.p8");
InputStream IAPKeyStream = classPathResource.getStream();
String content = IOUtils.toString(IAPKeyStream, String.valueOf(StandardCharsets.UTF_8));
String privateKey = content
.replace("-----BEGIN PRIVATE KEY-----", "")
.replaceAll("\\R+", "")
.replace("-----END PRIVATE KEY-----", "");
KeyFactory keyFactory = KeyFactory.getInstance("EC");
byte[] privateKeyBytes = Base64.getDecoder().decode(privateKey);
PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(privateKeyBytes);
ECPrivateKey ecPrivateKey = (ECPrivateKey) keyFactory.generatePrivate(keySpec);
return JWT.create()
.withHeader(jwtHeader)
.withPayload(jwtPayload)
.sign(Algorithm.ECDSA256(ecPrivateKey));
} catch (IOException | NoSuchAlgorithmException | InvalidKeySpecException e) {
throw new RuntimeException(e);
}
}
}

View File

@ -0,0 +1,6 @@
-----BEGIN PRIVATE KEY-----
MIGTAgEAMBMGByqGSM49AgEGCCqGSM49AwEHBHkwdwIBAQQggG04243qynU/yWYy
XpYVy9ZWMuLKzZiwhXCBWQBCOLigCgYIKoZIzj0DAQehRANCAARNln2/d+TM2pIO
LWQzvI77gPAVEvVCSlIuiJ+J7CJSG5KCysBaEeiiD5cc4dZWnUBijF8FBh7nDLaH
VwFXfrS+
-----END PRIVATE KEY-----

View File

@ -0,0 +1,110 @@
package com.sf.service.controller;
import java.util.List;
import javax.servlet.http.HttpServletResponse;
import apijson.orm.model.Request;
import com.sf.common.enums.RequestHeaderEnums;
import com.sf.common.utils.StringUtils;
import com.sf.common.utils.http.RequestUtils;
import com.sf.service.domain.GoodsMessages;
import com.sf.service.service.IGoodsMessagesService;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.PutMapping;
import org.springframework.web.bind.annotation.DeleteMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import com.sf.common.annotation.Log;
import com.sf.common.core.controller.BaseController;
import com.sf.common.core.domain.AjaxResult;
import com.sf.common.enums.BusinessType;
import com.sf.common.utils.poi.ExcelUtil;
import com.sf.common.core.page.TableDataInfo;
/**
* 商品信息Controller
*
* @author zoukun
* @date 2024-04-18
*/
@RestController
@RequestMapping("/service/goods")
public class GoodsMessagesController extends BaseController
{
@Autowired
private IGoodsMessagesService goodsMessagesService;
/**
* 查询商品信息列表
*/
@GetMapping("/list")
public TableDataInfo list(GoodsMessages goodsMessages)
{
goodsMessages.setAppCode(RequestUtils.getHeader(RequestHeaderEnums.APP_CODE.getCode()));
startPage();
List<GoodsMessages> list = goodsMessagesService.selectGoodsMessagesList(goodsMessages);
return getDataTable(list);
}
/**
* 导出商品信息列表
*/
@PreAuthorize("@ss.hasPermi('service:goods:export')")
@Log(title = "商品信息", businessType = BusinessType.EXPORT)
@PostMapping("/export")
public void export(HttpServletResponse response, GoodsMessages goodsMessages)
{
List<GoodsMessages> list = goodsMessagesService.selectGoodsMessagesList(goodsMessages);
ExcelUtil<GoodsMessages> util = new ExcelUtil<GoodsMessages>(GoodsMessages.class);
util.exportExcel(response, list, "商品信息数据");
}
/**
* 获取商品信息详细信息
*/
@PreAuthorize("@ss.hasPermi('service:goods:query')")
@GetMapping(value = "/{id}")
public AjaxResult getInfo(@PathVariable("id") Long id)
{
return success(goodsMessagesService.selectGoodsMessagesById(id));
}
/**
* 新增商品信息
*/
@PreAuthorize("@ss.hasPermi('service:goods:add')")
@Log(title = "商品信息", businessType = BusinessType.INSERT)
@PostMapping
public AjaxResult add(@RequestBody GoodsMessages goodsMessages)
{
goodsMessages.setAppCode(RequestUtils.getHeader(RequestHeaderEnums.APP_CODE.getCode()));
return toAjax(goodsMessagesService.insertGoodsMessages(goodsMessages));
}
/**
* 修改商品信息
*/
@PreAuthorize("@ss.hasPermi('service:goods:edit')")
@Log(title = "商品信息", businessType = BusinessType.UPDATE)
@PutMapping
public AjaxResult edit(@RequestBody GoodsMessages goodsMessages)
{
return toAjax(goodsMessagesService.updateGoodsMessages(goodsMessages));
}
/**
* 删除商品信息
*/
@PreAuthorize("@ss.hasPermi('service:goods:remove')")
@Log(title = "商品信息", businessType = BusinessType.DELETE)
@DeleteMapping("/{ids}")
public AjaxResult remove(@PathVariable Long[] ids)
{
return toAjax(goodsMessagesService.deleteGoodsMessagesByIds(ids));
}
}

View File

@ -0,0 +1,254 @@
package com.sf.service.domain;
import org.apache.commons.lang3.builder.ToStringBuilder;
import org.apache.commons.lang3.builder.ToStringStyle;
import com.sf.common.annotation.Excel;
import com.sf.common.core.domain.BaseEntity;
/**
* 商品信息对象 GOODS_MESSAGES
*
* @author zoukun
* @date 2024-04-18
*/
public class GoodsMessages extends BaseEntity
{
private static final long serialVersionUID = 1L;
/** 主键 */
private Long id;
/** 应用id */
private String appCode;
/** 商品编号 */
@Excel(name = "商品编号")
private String goodsCode;
/** 库存表编号 */
private Long stockId;
/** 审核状态1通过0未通过 */
@Excel(name = "审核状态1通过0未通过")
private Long reviewStatus;
/** 商品标题 */
@Excel(name = "商品标题")
private String productTitle;
/** 商品图片 */
@Excel(name = "商品图片")
private String productPicture;
/** 商品原价 */
@Excel(name = "商品原价")
private Long originalPrice;
/** 商品描述 */
@Excel(name = "商品描述")
private String productDesc;
/** 商品类型。 * • 0消耗型商品 * • 1非消耗型商品 * • 2自动续期订阅商品 */
@Excel(name = "商品类型。 * • 0消耗型商品 * • 1非消耗型商品 * • 2自动续期订阅商品")
private Integer goodsType;
/** 商品规格 */
@Excel(name = "商品规格")
private String goodsSpec;
/** 排序 */
private Long orderNum;
/** 逻辑删除,0:未删除,1:删除 */
private Long isDelete;
/** 创建人 */
private String created;
/** 更新人 */
private String modified;
/** 商品名称 */
private String goodsName;
/** 商品型号 */
@Excel(name = "商品型号")
private String goodsModel;
public void setId(Long id)
{
this.id = id;
}
public Long getId()
{
return id;
}
public void setGoodsCode(String goodsCode)
{
this.goodsCode = goodsCode;
}
public String getGoodsCode()
{
return goodsCode;
}
public void setStockId(Long stockId)
{
this.stockId = stockId;
}
public Long getStockId()
{
return stockId;
}
public void setReviewStatus(Long reviewStatus)
{
this.reviewStatus = reviewStatus;
}
public Long getReviewStatus()
{
return reviewStatus;
}
public void setProductTitle(String productTitle)
{
this.productTitle = productTitle;
}
public String getProductTitle()
{
return productTitle;
}
public void setProductPicture(String productPicture)
{
this.productPicture = productPicture;
}
public String getProductPicture()
{
return productPicture;
}
public void setOriginalPrice(Long originalPrice)
{
this.originalPrice = originalPrice;
}
public Long getOriginalPrice()
{
return originalPrice;
}
public void setProductDesc(String productDesc)
{
this.productDesc = productDesc;
}
public String getProductDesc()
{
return productDesc;
}
public void setGoodsType(Integer goodsType)
{
this.goodsType = goodsType;
}
public Integer getGoodsType()
{
return goodsType;
}
public void setGoodsSpec(String goodsSpec)
{
this.goodsSpec = goodsSpec;
}
public String getGoodsSpec()
{
return goodsSpec;
}
public void setOrderNum(Long orderNum)
{
this.orderNum = orderNum;
}
public Long getOrderNum()
{
return orderNum;
}
public void setIsDelete(Long isDelete)
{
this.isDelete = isDelete;
}
public Long getIsDelete()
{
return isDelete;
}
public void setCreated(String created)
{
this.created = created;
}
public String getCreated()
{
return created;
}
public void setModified(String modified)
{
this.modified = modified;
}
public String getModified()
{
return modified;
}
public void setGoodsName(String goodsName)
{
this.goodsName = goodsName;
}
public String getGoodsName()
{
return goodsName;
}
public void setGoodsModel(String goodsModel)
{
this.goodsModel = goodsModel;
}
public String getGoodsModel()
{
return goodsModel;
}
public String getAppCode() {
return appCode;
}
public void setAppCode(String appCode) {
this.appCode = appCode;
}
@Override
public String toString() {
return new ToStringBuilder(this,ToStringStyle.MULTI_LINE_STYLE)
.append("id", getId())
.append("appCode", getAppCode())
.append("goodsCode", getGoodsCode())
.append("stockId", getStockId())
.append("reviewStatus", getReviewStatus())
.append("productTitle", getProductTitle())
.append("productPicture", getProductPicture())
.append("originalPrice", getOriginalPrice())
.append("productDesc", getProductDesc())
.append("goodsType", getGoodsType())
.append("goodsSpec", getGoodsSpec())
.append("orderNum", getOrderNum())
.append("isDelete", getIsDelete())
.append("created", getCreated())
.append("modified", getModified())
.append("createTime", getCreateTime())
.append("updateTime", getUpdateTime())
.append("goodsName", getGoodsName())
.append("goodsModel", getGoodsModel())
.toString();
}
}

View File

@ -0,0 +1,63 @@
package com.sf.service.mapper;
import java.util.List;
import com.sf.service.domain.GoodsMessages;
/**
* 商品信息Mapper接口
*
* @author zoukun
* @date 2024-04-18
*/
public interface GoodsMessagesMapper
{
/**
* 查询商品信息
*
* @param id 商品信息主键
* @return 商品信息
*/
public GoodsMessages selectGoodsMessagesById(Long id);
/**
* 查询商品信息列表
*
* @param goodsMessages 商品信息
* @return 商品信息集合
*/
public List<GoodsMessages> selectGoodsMessagesList(GoodsMessages goodsMessages);
/**
* 新增商品信息
*
* @param goodsMessages 商品信息
* @return 结果
*/
public int insertGoodsMessages(GoodsMessages goodsMessages);
/**
* 修改商品信息
*
* @param goodsMessages 商品信息
* @return 结果
*/
public int updateGoodsMessages(GoodsMessages goodsMessages);
/**
* 删除商品信息
*
* @param id 商品信息主键
* @return 结果
*/
public int deleteGoodsMessagesById(Long id);
/**
* 批量删除商品信息
*
* @param ids 需要删除的数据主键集合
* @return 结果
*/
public int deleteGoodsMessagesByIds(Long[] ids);
GoodsMessages selectGoodsMessagesByCode(String goodsCode);
}

View File

@ -0,0 +1,63 @@
package com.sf.service.service;
import java.util.List;
import com.sf.service.domain.GoodsMessages;
/**
* 商品信息Service接口
*
* @author zoukun
* @date 2024-04-18
*/
public interface IGoodsMessagesService
{
/**
* 查询商品信息
*
* @param id 商品信息主键
* @return 商品信息
*/
public GoodsMessages selectGoodsMessagesById(Long id);
/**
* 查询商品信息列表
*
* @param goodsMessages 商品信息
* @return 商品信息集合
*/
public List<GoodsMessages> selectGoodsMessagesList(GoodsMessages goodsMessages);
/**
* 新增商品信息
*
* @param goodsMessages 商品信息
* @return 结果
*/
public int insertGoodsMessages(GoodsMessages goodsMessages);
/**
* 修改商品信息
*
* @param goodsMessages 商品信息
* @return 结果
*/
public int updateGoodsMessages(GoodsMessages goodsMessages);
/**
* 批量删除商品信息
*
* @param ids 需要删除的商品信息主键集合
* @return 结果
*/
public int deleteGoodsMessagesByIds(Long[] ids);
/**
* 删除商品信息信息
*
* @param id 商品信息主键
* @return 结果
*/
public int deleteGoodsMessagesById(Long id);
GoodsMessages selectGoodsMessagesByCode(String goodsCode);
}

View File

@ -0,0 +1,105 @@
package com.sf.service.service.impl;
import java.util.List;
import com.sf.common.utils.DateUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import com.sf.service.mapper.GoodsMessagesMapper;
import com.sf.service.domain.GoodsMessages;
import com.sf.service.service.IGoodsMessagesService;
import org.springframework.util.StringUtils;
/**
* 商品信息Service业务层处理
*
* @author zoukun
* @date 2024-04-18
*/
@Service
public class GoodsMessagesServiceImpl implements IGoodsMessagesService
{
@Autowired
private GoodsMessagesMapper goodsMessagesMapper;
/**
* 查询商品信息
*
* @param id 商品信息主键
* @return 商品信息
*/
@Override
public GoodsMessages selectGoodsMessagesById(Long id)
{
return goodsMessagesMapper.selectGoodsMessagesById(id);
}
/**
* 查询商品信息列表
*
* @param goodsMessages 商品信息
* @return 商品信息
*/
@Override
public List<GoodsMessages> selectGoodsMessagesList(GoodsMessages goodsMessages)
{
return goodsMessagesMapper.selectGoodsMessagesList(goodsMessages);
}
/**
* 新增商品信息
*
* @param goodsMessages 商品信息
* @return 结果
*/
@Override
public int insertGoodsMessages(GoodsMessages goodsMessages)
{
goodsMessages.setCreateTime(DateUtils.getNowDate());
return goodsMessagesMapper.insertGoodsMessages(goodsMessages);
}
/**
* 修改商品信息
*
* @param goodsMessages 商品信息
* @return 结果
*/
@Override
public int updateGoodsMessages(GoodsMessages goodsMessages)
{
goodsMessages.setUpdateTime(DateUtils.getNowDate());
return goodsMessagesMapper.updateGoodsMessages(goodsMessages);
}
/**
* 批量删除商品信息
*
* @param ids 需要删除的商品信息主键
* @return 结果
*/
@Override
public int deleteGoodsMessagesByIds(Long[] ids)
{
return goodsMessagesMapper.deleteGoodsMessagesByIds(ids);
}
/**
* 删除商品信息信息
*
* @param id 商品信息主键
* @return 结果
*/
@Override
public int deleteGoodsMessagesById(Long id)
{
return goodsMessagesMapper.deleteGoodsMessagesById(id);
}
@Override
public GoodsMessages selectGoodsMessagesByCode(String goodsCode) {
if (StringUtils.hasText(goodsCode)){
return goodsMessagesMapper.selectGoodsMessagesByCode(goodsCode);
}
return null;
}
}

View File

@ -0,0 +1,134 @@
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.sf.service.mapper.GoodsMessagesMapper">
<resultMap type="GoodsMessages" id="GoodsMessagesResult">
<result property="id" column="id" />
<result property="appCode" column="app_code" />
<result property="goodsCode" column="goods_code" />
<result property="stockId" column="stock_id" />
<result property="reviewStatus" column="review_status" />
<result property="productTitle" column="product_title" />
<result property="productPicture" column="product_picture" />
<result property="originalPrice" column="original_price" />
<result property="productDesc" column="product_desc" />
<result property="goodsType" column="goods_type" />
<result property="goodsSpec" column="goods_spec" />
<result property="orderNum" column="order_num" />
<result property="isDelete" column="is_delete" />
<result property="created" column="created" />
<result property="modified" column="modified" />
<result property="createTime" column="create_time" />
<result property="updateTime" column="update_time" />
<result property="goodsName" column="goods_name" />
<result property="goodsModel" column="goods_model" />
</resultMap>
<sql id="selectGoodsMessagesVo">
select id, app_code, goods_code, stock_id, review_status, product_title, product_picture, original_price, product_desc, goods_type, goods_spec, order_num, is_delete, created, modified, create_time, update_time, goods_name, goods_model from GOODS_MESSAGES
</sql>
<select id="selectGoodsMessagesList" parameterType="GoodsMessages" resultMap="GoodsMessagesResult">
<include refid="selectGoodsMessagesVo"/>
<where>
<if test="appCode != null and appCode != ''"> and app_code = #{appCode}</if>
<if test="goodsCode != null and goodsCode != ''"> and goods_code = #{goodsCode}</if>
<if test="reviewStatus != null "> and review_status = #{reviewStatus}</if>
<if test="productTitle != null and productTitle != ''"> and product_title like concat('%', #{productTitle}, '%')</if>
<if test="params.beginOriginalPrice != null and params.beginOriginalPrice != '' and params.endOriginalPrice != null and params.endOriginalPrice != ''"> and original_price between #{params.beginOriginalPrice} and #{params.endOriginalPrice}</if>
<if test="goodsType != null "> and goods_type = #{goodsType}</if>
<if test="goodsSpec != null and goodsSpec != ''"> and goods_spec = #{goodsSpec}</if>
<if test="goodsModel != null and goodsModel != ''"> and goods_model = #{goodsModel}</if>
</where>
</select>
<select id="selectGoodsMessagesById" parameterType="Long" resultMap="GoodsMessagesResult">
<include refid="selectGoodsMessagesVo"/>
where id = #{id}
</select>
<select id="selectGoodsMessagesByCode" parameterType="String" resultMap="GoodsMessagesResult">
<include refid="selectGoodsMessagesVo"/>
where goods_code = #{goodsCode} limit 1
</select>
<insert id="insertGoodsMessages" parameterType="GoodsMessages" useGeneratedKeys="true" keyProperty="id">
insert into GOODS_MESSAGES
<trim prefix="(" suffix=")" suffixOverrides=",">
<if test="appCode != null and appCode != ''">app_code,</if>
<if test="goodsCode != null and goodsCode != ''">goods_code,</if>
<if test="stockId != null">stock_id,</if>
<if test="reviewStatus != null">review_status,</if>
<if test="productTitle != null and productTitle != ''">product_title,</if>
<if test="productPicture != null and productPicture != ''">product_picture,</if>
<if test="originalPrice != null">original_price,</if>
<if test="productDesc != null">product_desc,</if>
<if test="goodsType != null">goods_type,</if>
<if test="goodsSpec != null and goodsSpec != ''">goods_spec,</if>
<if test="orderNum != null">order_num,</if>
<if test="isDelete != null">is_delete,</if>
<if test="created != null">created,</if>
<if test="modified != null">modified,</if>
<if test="createTime != null">create_time,</if>
<if test="updateTime != null">update_time,</if>
<if test="goodsName != null and goodsName != ''">goods_name,</if>
<if test="goodsModel != null">goods_model,</if>
</trim>
<trim prefix="values (" suffix=")" suffixOverrides=",">
<if test="appCode != null and appCode != ''">#{appCode},</if>
<if test="goodsCode != null and goodsCode != ''">#{goodsCode},</if>
<if test="stockId != null">#{stockId},</if>
<if test="reviewStatus != null">#{reviewStatus},</if>
<if test="productTitle != null and productTitle != ''">#{productTitle},</if>
<if test="productPicture != null and productPicture != ''">#{productPicture},</if>
<if test="originalPrice != null">#{originalPrice},</if>
<if test="productDesc != null">#{productDesc},</if>
<if test="goodsType != null">#{goodsType},</if>
<if test="goodsSpec != null and goodsSpec != ''">#{goodsSpec},</if>
<if test="orderNum != null">#{orderNum},</if>
<if test="isDelete != null">#{isDelete},</if>
<if test="created != null">#{created},</if>
<if test="modified != null">#{modified},</if>
<if test="createTime != null">#{createTime},</if>
<if test="updateTime != null">#{updateTime},</if>
<if test="goodsName != null and goodsName != ''">#{goodsName},</if>
<if test="goodsModel != null">#{goodsModel},</if>
</trim>
</insert>
<update id="updateGoodsMessages" parameterType="GoodsMessages">
update GOODS_MESSAGES
<trim prefix="SET" suffixOverrides=",">
<if test="goodsCode != null and goodsCode != ''">goods_code = #{goodsCode},</if>
<if test="stockId != null">stock_id = #{stockId},</if>
<if test="reviewStatus != null">review_status = #{reviewStatus},</if>
<if test="productTitle != null and productTitle != ''">product_title = #{productTitle},</if>
<if test="productPicture != null and productPicture != ''">product_picture = #{productPicture},</if>
<if test="originalPrice != null">original_price = #{originalPrice},</if>
<if test="productDesc != null">product_desc = #{productDesc},</if>
<if test="goodsType != null">goods_type = #{goodsType},</if>
<if test="goodsSpec != null and goodsSpec != ''">goods_spec = #{goodsSpec},</if>
<if test="orderNum != null">order_num = #{orderNum},</if>
<if test="isDelete != null">is_delete = #{isDelete},</if>
<if test="created != null">created = #{created},</if>
<if test="modified != null">modified = #{modified},</if>
<if test="createTime != null">create_time = #{createTime},</if>
<if test="updateTime != null">update_time = #{updateTime},</if>
<if test="goodsName != null and goodsName != ''">goods_name = #{goodsName},</if>
<if test="goodsModel != null">goods_model = #{goodsModel},</if>
</trim>
where id = #{id}
</update>
<delete id="deleteGoodsMessagesById" parameterType="Long">
delete from GOODS_MESSAGES where id = #{id}
</delete>
<delete id="deleteGoodsMessagesByIds" parameterType="String">
delete from GOODS_MESSAGES where id in
<foreach item="id" collection="array" open="(" separator="," close=")">
#{id}
</foreach>
</delete>
</mapper>

View File

@ -22,6 +22,10 @@
<groupId>com.smarterFramework</groupId>
<artifactId>sf-common</artifactId>
</dependency>
<dependency>
<groupId>com.smarterFramework</groupId>
<artifactId>sf-file</artifactId>
</dependency>
</dependencies>

View File

@ -1,28 +1,35 @@
package com.sf.system.deployment.controller;
import java.util.List;
import javax.servlet.ServletRequest;
import javax.servlet.ServletRequestAttributeEvent;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.springframework.beans.factory.annotation.Autowired;
import com.sf.common.enums.RequestHeaderEnums;
import com.sf.common.utils.StringUtils;
import com.sf.common.utils.http.RequestUtils;
import com.sf.system.deployment.domain.DeploymentApplyEnvironment;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.web.bind.annotation.DeleteMapping;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.PutMapping;
import org.springframework.web.bind.annotation.DeleteMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import com.sf.common.annotation.Log;
import com.sf.common.core.controller.BaseController;
import com.sf.common.core.domain.AjaxResult;
import com.sf.common.core.page.TableDataInfo;
import com.sf.common.enums.BusinessType;
import com.sf.deployment.service.IDeploymentApplyEnvironmentService;
import com.sf.common.utils.poi.ExcelUtil;
import com.sf.system.deployment.domain.DeploymentApplyEnvironment;
import com.sf.system.deployment.service.IDeploymentApplyEnvironmentService;
import com.sf.common.core.page.TableDataInfo;
import org.springframework.web.context.request.RequestAttributes;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
/**
* 环境维护Controller
@ -44,6 +51,7 @@ public class DeploymentApplyEnvironmentController extends BaseController
@GetMapping("/list")
public TableDataInfo list(DeploymentApplyEnvironment deploymentApplyEnvironment)
{
deploymentApplyEnvironment.setAppCode(RequestUtils.getHeader(RequestHeaderEnums.APP_CODE.getCode()));
startPage();
List<DeploymentApplyEnvironment> list = deploymentApplyEnvironmentService.selectDeploymentApplyEnvironmentList(deploymentApplyEnvironment);
return getDataTable(list);
@ -80,6 +88,7 @@ public class DeploymentApplyEnvironmentController extends BaseController
@PostMapping
public AjaxResult add(@RequestBody DeploymentApplyEnvironment deploymentApplyEnvironment)
{
deploymentApplyEnvironment.setAppCode( RequestUtils.getHeader(RequestHeaderEnums.APP_CODE.getCode()));
return toAjax(deploymentApplyEnvironmentService.insertDeploymentApplyEnvironment(deploymentApplyEnvironment));
}

View File

@ -0,0 +1,162 @@
package com.sf.system.deployment.controller;
import java.io.InputStream;
import java.net.URL;
import java.util.List;
import java.util.concurrent.TimeUnit;
import javax.servlet.http.HttpServletResponse;
import com.sf.common.core.redis.RedisCache;
import com.sf.common.enums.RequestHeaderEnums;
import com.sf.common.utils.http.RequestUtils;
import com.sf.common.utils.openssl.AES256Util;
import com.sf.common.utils.uuid.UUID;
import com.sf.system.deployment.domain.rqs.ModuleListByCoreRequest;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.util.FileCopyUtils;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.PutMapping;
import org.springframework.web.bind.annotation.DeleteMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import com.sf.common.annotation.Log;
import com.sf.common.core.controller.BaseController;
import com.sf.common.core.domain.AjaxResult;
import com.sf.common.enums.BusinessType;
import com.sf.system.deployment.domain.DeploymentModuleList;
import com.sf.system.deployment.service.IDeploymentModuleListService;
import com.sf.common.utils.poi.ExcelUtil;
import com.sf.common.core.page.TableDataInfo;
/**
* H5模块包Controller
*
* @author ztzh
* @date 2024-04-22
*/
@RestController
@RequestMapping("/deployment/module")
public class DeploymentModuleListController extends BaseController {
@Autowired
private IDeploymentModuleListService deploymentModuleListService;
@Autowired
private RedisCache redisCache;
/**
* 查询H5模块包列表
*/
@PreAuthorize("@ss.hasPermi('deployment:module:list')")
@GetMapping("/list")
public TableDataInfo list(DeploymentModuleList deploymentModuleList) {
deploymentModuleList.setAppCode(RequestUtils.getHeader(RequestHeaderEnums.APP_CODE.getCode()));
startPage();
List<DeploymentModuleList> list = deploymentModuleListService.selectDeploymentModuleListList(deploymentModuleList);
return getDataTable(list);
}
/**
* 查询H5模块包列表
*/
@GetMapping("/qurey/list")
public AjaxResult queryByCore(ModuleListByCoreRequest request) {
DeploymentModuleList deploymentModuleList = new DeploymentModuleList();
deploymentModuleList.setAppCode(RequestUtils.getHeader(RequestHeaderEnums.APP_CODE.getCode()));
deploymentModuleList.setSysType(request.getSysType());
List<DeploymentModuleList> list = deploymentModuleListService.selectDeploymentModuleListList(deploymentModuleList);
return success(list);
}
/**
* 查询模块包列表
*/
@GetMapping("/qurey/file")
public AjaxResult queryByCore(ModuleListByCoreRequest request, HttpServletResponse response) {
DeploymentModuleList deploymentModuleList = new DeploymentModuleList();
deploymentModuleList.setAppCode(RequestUtils.getHeader(RequestHeaderEnums.APP_CODE.getCode()));
String authorization = RequestUtils.getHeader(RequestHeaderEnums.AUTHORIZATION.getCode());
deploymentModuleList.setSysType(request.getSysType());
deploymentModuleList.setModuleType(request.getModuleType());
List<DeploymentModuleList> list = deploymentModuleListService.selectDeploymentModuleListList(deploymentModuleList);
if (list.isEmpty() && null == list.get(0)) {
throw new SecurityException("无可用模块包");
}
try {
String password = UUID.randomUUID().toString().trim().replaceAll("-", "");
//加密
InputStream inputStream1 = AES256Util.encryptFile(password, new URL(list.get(0).getModuleUrl()).openStream());
FileCopyUtils.copy(inputStream1, response.getOutputStream());
redisCache.setCacheObject(authorization + request.getModuleType(), password, 3000, TimeUnit.MINUTES);
} catch (Exception e) {
throw new RuntimeException(e);
}
return success(null);
}
/**
* 获取压缩包密码
*/
@GetMapping("/qurey/ZipCore")
public AjaxResult queryZipCore(ModuleListByCoreRequest request) {
String authorization = RequestUtils.getHeader(RequestHeaderEnums.AUTHORIZATION.getCode());
String cacheObject = redisCache.getCacheObject(authorization + request.getModuleType());
return success(UUID.randomUUID().toString().trim().replaceAll("-", "") + cacheObject + UUID.randomUUID().toString().trim().replaceAll("-", ""))
;
}
/**
* 导出H5模块包列表
*/
@PreAuthorize("@ss.hasPermi('deployment:module:export')")
@Log(title = "H5模块包", businessType = BusinessType.EXPORT)
@PostMapping("/export")
public void export(HttpServletResponse response, DeploymentModuleList deploymentModuleList) {
List<DeploymentModuleList> list = deploymentModuleListService.selectDeploymentModuleListList(deploymentModuleList);
ExcelUtil<DeploymentModuleList> util = new ExcelUtil<DeploymentModuleList>(DeploymentModuleList.class);
util.exportExcel(response, list, "H5模块包数据");
}
/**
* 获取H5模块包详细信息
*/
@PreAuthorize("@ss.hasPermi('deployment:module:query')")
@GetMapping(value = "/{id}")
public AjaxResult getInfo(@PathVariable("id") Long id) {
return success(deploymentModuleListService.selectDeploymentModuleListById(id));
}
/**
* 新增H5模块包
*/
@PreAuthorize("@ss.hasPermi('deployment:module:add')")
@Log(title = "H5模块包", businessType = BusinessType.INSERT)
@PostMapping
public AjaxResult add(@RequestBody DeploymentModuleList deploymentModuleList) {
deploymentModuleList.setAppCode(RequestUtils.getHeader(RequestHeaderEnums.APP_CODE.getCode()));
return toAjax(deploymentModuleListService.insertDeploymentModuleList(deploymentModuleList));
}
/**
* 修改H5模块包
*/
@PreAuthorize("@ss.hasPermi('deployment:module:edit')")
@Log(title = "H5模块包", businessType = BusinessType.UPDATE)
@PutMapping
public AjaxResult edit(@RequestBody DeploymentModuleList deploymentModuleList) {
return toAjax(deploymentModuleListService.updateDeploymentModuleList(deploymentModuleList));
}
/**
* 删除H5模块包
*/
@PreAuthorize("@ss.hasPermi('deployment:module:remove')")
@Log(title = "H5模块包", businessType = BusinessType.DELETE)
@DeleteMapping("/{ids}")
public AjaxResult remove(@PathVariable Long[] ids) {
return toAjax(deploymentModuleListService.deleteDeploymentModuleListByIds(ids));
}
}

View File

@ -3,10 +3,15 @@ package com.sf.system.deployment.controller;
import java.util.List;
import javax.servlet.http.HttpServletResponse;
import com.sf.common.enums.RequestHeaderEnums;
import com.sf.common.utils.DateUtils;
import com.sf.common.utils.StringUtils;
import com.sf.common.utils.http.RequestUtils;
import com.sf.system.deployment.domain.DeploymentServicePublish;
import com.sf.system.deployment.service.IDeploymentServicePublishService;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.util.unit.DataUnit;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.PutMapping;
@ -42,6 +47,7 @@ public class DeploymentServicePublishController extends BaseController
@GetMapping("/list")
public TableDataInfo list(DeploymentServicePublish deploymentServicePublish)
{
deploymentServicePublish.setAppCode(RequestUtils.getHeader(RequestHeaderEnums.APP_CODE.getCode()));
startPage();
List<DeploymentServicePublish> list = deploymentServicePublishService.selectDeploymentServicePublishList(deploymentServicePublish);
return getDataTable(list);
@ -78,6 +84,7 @@ public class DeploymentServicePublishController extends BaseController
@PostMapping
public AjaxResult add(@RequestBody DeploymentServicePublish deploymentServicePublish)
{
deploymentServicePublish.setAppCode(RequestUtils.getHeader(RequestHeaderEnums.APP_CODE.getCode()));
return toAjax(deploymentServicePublishService.insertDeploymentServicePublish(deploymentServicePublish));
}
@ -102,4 +109,30 @@ public class DeploymentServicePublishController extends BaseController
{
return toAjax(deploymentServicePublishService.deleteDeploymentServicePublishByIds(ids));
}
/**
* 发布功能
*/
@PreAuthorize("@ss.hasPermi('deployment:publish:publish')")
@GetMapping(value = "/publish/{id}")
public AjaxResult publish(@PathVariable("id") Long id) throws Exception {
DeploymentServicePublish deploymentServicePublish = deploymentServicePublishService.selectDeploymentServicePublishById(id);
// deploymentServicePublish.setUpdateBy(getUsername());
deploymentServicePublish.setUpdateTime(DateUtils.getNowDate());
return success(deploymentServicePublishService.publish(deploymentServicePublish));
}
/**
* 下架
*/
@PreAuthorize("@ss.hasPermi('deployment:publish:sold:out')")
@GetMapping(value = "/sold/out/{id}")
public AjaxResult soldOut(@PathVariable("id") Long id)
{
DeploymentServicePublish deploymentServicePublish = deploymentServicePublishService.selectDeploymentServicePublishById(id);
// deploymentServicePublish.setUpdateBy(getUsername());
deploymentServicePublish.setUpdateTime(DateUtils.getNowDate());
return success(deploymentServicePublishService.soldOut(deploymentServicePublish));
}
}

View File

@ -0,0 +1,128 @@
package com.sf.system.deployment.controller;
import java.util.List;
import javax.servlet.http.HttpServletResponse;
import com.sf.common.enums.RequestHeaderEnums;
import com.sf.common.utils.http.RequestUtils;
import com.sf.system.deployment.domain.DeploymentWhitelistInfo;
import com.sf.system.deployment.service.IDeploymentWhitelistInfoService;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.PutMapping;
import org.springframework.web.bind.annotation.DeleteMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import com.sf.common.annotation.Log;
import com.sf.common.core.controller.BaseController;
import com.sf.common.core.domain.AjaxResult;
import com.sf.common.enums.BusinessType;
import com.sf.common.utils.poi.ExcelUtil;
import com.sf.common.core.page.TableDataInfo;
/**
* 白名单列表Controller
*
* @author ztzh
* @date 2024-05-06
*/
@RestController
@RequestMapping("/deployment/whitelist")
public class DeploymentWhitelistInfoController extends BaseController
{
@Autowired
private IDeploymentWhitelistInfoService deploymentWhitelistInfoService;
/**
* 查询白名单列表列表
*/
@PreAuthorize("@ss.hasPermi('deployment:whitelist:list')")
@GetMapping("/list")
public TableDataInfo list(DeploymentWhitelistInfo deploymentWhitelistInfo)
{
deploymentWhitelistInfo.setAppCode(RequestUtils.getHeader(RequestHeaderEnums.APP_CODE.getCode()));
startPage();
List<DeploymentWhitelistInfo> list = deploymentWhitelistInfoService.selectDeploymentWhitelistInfoList(deploymentWhitelistInfo);
return getDataTable(list);
}
/**
* 导出白名单列表列表
*/
@PreAuthorize("@ss.hasPermi('deployment:whitelist:export')")
@Log(title = "白名单列表", businessType = BusinessType.EXPORT)
@PostMapping("/export")
public void export(HttpServletResponse response, DeploymentWhitelistInfo deploymentWhitelistInfo)
{
deploymentWhitelistInfo.setAppCode(RequestUtils.getHeader(RequestHeaderEnums.APP_CODE.getCode()));
List<DeploymentWhitelistInfo> list = deploymentWhitelistInfoService.selectDeploymentWhitelistInfoList(deploymentWhitelistInfo);
ExcelUtil<DeploymentWhitelistInfo> util = new ExcelUtil<DeploymentWhitelistInfo>(DeploymentWhitelistInfo.class);
util.exportExcel(response, list, "白名单列表数据");
}
/**
* 获取白名单列表详细信息
*/
@PreAuthorize("@ss.hasPermi('deployment:whitelist:query')")
@GetMapping(value = "/{id}")
public AjaxResult getInfo(@PathVariable("id") Long id)
{
return success(deploymentWhitelistInfoService.selectDeploymentWhitelistInfoById(id));
}
/**
* 新增白名单列表
*/
@PreAuthorize("@ss.hasPermi('deployment:whitelist:add')")
@Log(title = "白名单列表", businessType = BusinessType.INSERT)
@PostMapping
public AjaxResult add(@RequestBody DeploymentWhitelistInfo deploymentWhitelistInfo)
{
deploymentWhitelistInfo.setAppCode(RequestUtils.getHeader(RequestHeaderEnums.APP_CODE.getCode()));
return toAjax(deploymentWhitelistInfoService.insertDeploymentWhitelistInfo(deploymentWhitelistInfo));
}
/**
* 修改白名单列表
*/
@PreAuthorize("@ss.hasPermi('deployment:whitelist:edit')")
@Log(title = "白名单列表", businessType = BusinessType.UPDATE)
@PutMapping
public AjaxResult edit(@RequestBody DeploymentWhitelistInfo deploymentWhitelistInfo)
{
return toAjax(deploymentWhitelistInfoService.updateDeploymentWhitelistInfo(deploymentWhitelistInfo));
}
/**
* 删除白名单列表
*/
@PreAuthorize("@ss.hasPermi('deployment:whitelist:remove')")
@Log(title = "白名单列表", businessType = BusinessType.DELETE)
@DeleteMapping("/{ids}")
public AjaxResult remove(@PathVariable Long[] ids)
{
return toAjax(deploymentWhitelistInfoService.deleteDeploymentWhitelistInfoByIds(ids));
}
/**
* 发布功能
*/
@PreAuthorize("@ss.hasPermi('deployment:whitelist:publish')")
@GetMapping(value = "/publish/{id}")
public AjaxResult publish(@PathVariable("id") Long id) throws Exception {
return success(deploymentWhitelistInfoService.publish(id));
}
/**
* 下架功能
*/
@PreAuthorize("@ss.hasPermi('deployment:whitelist:sold:out')")
@GetMapping(value = "/sold/out/{id}")
public AjaxResult soldOut(@PathVariable("id") Long id)
{
return success(deploymentWhitelistInfoService.soldOut(id));
}
}

View File

@ -0,0 +1,121 @@
package com.sf.system.deployment.controller;
import java.io.IOException;
import java.util.List;
import javax.servlet.http.HttpServletResponse;
import cn.hutool.core.util.ObjectUtil;
import com.sf.common.exception.ServiceException;
import com.sf.system.deployment.domain.DeploymentWhitelistList;
import com.sf.system.deployment.service.IDeploymentWhitelistListService;
import org.springframework.http.MediaType;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import com.sf.common.annotation.Log;
import com.sf.common.core.controller.BaseController;
import com.sf.common.core.domain.AjaxResult;
import com.sf.common.enums.BusinessType;
import com.sf.common.utils.poi.ExcelUtil;
import com.sf.common.core.page.TableDataInfo;
import org.springframework.web.multipart.MultipartFile;
/**
* 白名单成员列Controller
*
* @author ztzh
* @date 2024-05-06
*/
@RestController
@RequestMapping("/deployment/whitelistMember")
public class DeploymentWhitelistListController extends BaseController
{
@Autowired
private IDeploymentWhitelistListService deploymentWhitelistListService;
/**
* 查询白名单成员列列表
*/
@PreAuthorize("@ss.hasPermi('deployment:whitelistMember:list')")
@GetMapping("/list")
public TableDataInfo list(DeploymentWhitelistList deploymentWhitelistList)
{
if(null == deploymentWhitelistList.getWhitelistId()){
throw new SecurityException("参数异常WhitelistId为空");
}
startPage();
List<DeploymentWhitelistList> list = deploymentWhitelistListService.selectDeploymentWhitelistListList(deploymentWhitelistList);
return getDataTable(list);
}
/**
* 导出白名单成员列列表
*/
@PreAuthorize("@ss.hasPermi('deployment:whitelistMember:export')")
@Log(title = "白名单成员列", businessType = BusinessType.EXPORT)
@PostMapping("/export")
public void export(HttpServletResponse response, DeploymentWhitelistList deploymentWhitelistList)
{
List<DeploymentWhitelistList> list = deploymentWhitelistListService.selectDeploymentWhitelistListList(deploymentWhitelistList);
ExcelUtil<DeploymentWhitelistList> util = new ExcelUtil<DeploymentWhitelistList>(DeploymentWhitelistList.class);
util.exportExcel(response, list, "白名单成员列数据");
}
/**
* 获取白名单成员列详细信息
*/
@PreAuthorize("@ss.hasPermi('deployment:whitelistMember:query')")
@GetMapping(value = "/{id}")
public AjaxResult getInfo(@PathVariable("id") Long id)
{
return success(deploymentWhitelistListService.selectDeploymentWhitelistListById(id));
}
/**
* 新增白名单成员列
*/
@PreAuthorize("@ss.hasPermi('deployment:whitelistMember:add')")
@Log(title = "白名单成员列", businessType = BusinessType.INSERT)
@PostMapping
public AjaxResult add(@RequestBody DeploymentWhitelistList deploymentWhitelistList)
{
return toAjax(deploymentWhitelistListService.insertDeploymentWhitelistList(deploymentWhitelistList,getUsername()));
}
/**
* 修改白名单成员列
*/
@PreAuthorize("@ss.hasPermi('deployment:whitelistMember:edit')")
@Log(title = "白名单成员列", businessType = BusinessType.UPDATE)
@PutMapping
public AjaxResult edit(@RequestBody DeploymentWhitelistList deploymentWhitelistList)
{
return toAjax(deploymentWhitelistListService.updateDeploymentWhitelistList(deploymentWhitelistList));
}
/**
* 删除白名单成员列
*/
@PreAuthorize("@ss.hasPermi('deployment:whitelistMember:remove')")
@Log(title = "白名单成员列", businessType = BusinessType.DELETE)
@DeleteMapping("/{ids}")
public AjaxResult remove(@PathVariable Long[] ids)
{
return toAjax(deploymentWhitelistListService.deleteDeploymentWhitelistListByIds(ids));
}
/**
* 批量导入
*
* @param file 文件
*/
@PreAuthorize("@ss.hasPermi('deployment:whitelistMember:batch:import')")
@Log(title = "批量上传", businessType = BusinessType.INSERT)
@PostMapping(value = "/batch/import", consumes = MediaType.MULTIPART_FORM_DATA_VALUE)
public AjaxResult batchImport(@RequestPart("file") MultipartFile file,Long whitelistId) throws IOException {
if (ObjectUtil.isNull(file)) {
throw new ServiceException("上传文件不能为空");
}
return toAjax(deploymentWhitelistListService.batchImport(file,whitelistId,getUsername()));
}
}

View File

@ -0,0 +1,106 @@
package com.sf.system.deployment.controller;
import com.sf.common.annotation.Log;
import com.sf.common.core.controller.BaseController;
import com.sf.common.core.domain.AjaxResult;
import com.sf.common.core.page.TableDataInfo;
import com.sf.common.enums.BusinessType;
import com.sf.common.enums.RequestHeaderEnums;
import com.sf.common.utils.StringUtils;
import com.sf.common.utils.http.RequestUtils;
import com.sf.common.utils.poi.ExcelUtil;
import com.sf.system.deployment.domain.SysApkInfo;
import com.sf.system.deployment.service.ISysApkInfoService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.web.bind.annotation.*;
import javax.servlet.http.HttpServletResponse;
import java.util.List;
/**
* 安装包管理Controller
*
* @author ztzh
* @date 2024-04-11
*/
@RestController
@RequestMapping("/deploy/INFO")
public class SysApkInfoController extends BaseController
{
@Autowired
private ISysApkInfoService sysApkInfoService;
/**
* 查询安装包管理列表
*/
@PreAuthorize("@ss.hasPermi('deploy:INFO:list')")
@GetMapping("/list")
public TableDataInfo list(SysApkInfo sysApkInfo)
{
sysApkInfo.setAppCode(RequestUtils.getHeader(RequestHeaderEnums.APP_CODE.getCode()));
startPage();
List<SysApkInfo> list = sysApkInfoService.selectSysApkInfoList(sysApkInfo);
return getDataTable(list);
}
/**
* 导出安装包管理列表
*/
@PreAuthorize("@ss.hasPermi('deploy:INFO:export')")
@Log(title = "安装包管理(新)", businessType = BusinessType.EXPORT)
@PostMapping("/export")
public void export(HttpServletResponse response, SysApkInfo sysApkInfo)
{
List<SysApkInfo> list = sysApkInfoService.selectSysApkInfoList(sysApkInfo);
ExcelUtil<SysApkInfo> util = new ExcelUtil<SysApkInfo>(SysApkInfo.class);
util.exportExcel(response, list, "安装包管理(新)数据");
}
/**
* 获取安装包管理详细信息
*/
@PreAuthorize("@ss.hasPermi('deploy:INFO:query')")
@GetMapping(value = "/{id}")
public AjaxResult getInfo(@PathVariable("id") Long id)
{
return success(sysApkInfoService.selectSysApkInfoById(id));
}
/**
* 新增安装包管理
*/
@PreAuthorize("@ss.hasPermi('deploy:INFO:add')")
@Log(title = "安装包管理(新)", businessType = BusinessType.INSERT)
@PostMapping
public AjaxResult add(@RequestBody SysApkInfo sysApkInfo)
{
sysApkInfo.setAppCode(RequestUtils.getHeader(RequestHeaderEnums.APP_CODE.getCode()));
sysApkInfo.setCreated(getUsername());
sysApkInfo.setModified(getUsername());
return toAjax(sysApkInfoService.insertSysApkInfo(sysApkInfo));
}
/**
* 修改安装包管理
*/
@PreAuthorize("@ss.hasPermi('deploy:INFO:edit')")
@Log(title = "安装包管理(新)", businessType = BusinessType.UPDATE)
@PutMapping
public AjaxResult edit(@RequestBody SysApkInfo sysApkInfo)
{
sysApkInfo.setModified(getUsername());
return toAjax(sysApkInfoService.updateSysApkInfo(sysApkInfo));
}
/**
* 删除安装包管理
*/
@PreAuthorize("@ss.hasPermi('deploy:INFO:remove')")
@Log(title = "安装包管理(新)", businessType = BusinessType.DELETE)
@DeleteMapping("/{ids}")
public AjaxResult remove(@PathVariable Long[] ids)
{
return toAjax(sysApkInfoService.deleteSysApkInfoByIds(ids));
}
}

View File

@ -22,7 +22,7 @@ public class DeploymentApplyEnvironment extends BaseEntity
private Long appId;
/** 应用编号 */
private String applyCode;
private String appCode;
/** 环境名称 */
@Excel(name = "环境名称")
@ -58,14 +58,14 @@ public class DeploymentApplyEnvironment extends BaseEntity
{
return appId;
}
public void setApplyCode(String applyCode)
public void setAppCode(String appCode)
{
this.applyCode = applyCode;
this.appCode = appCode;
}
public String getApplyCode()
public String getAppCode()
{
return applyCode;
return appCode;
}
public void setName(String name)
{
@ -109,7 +109,7 @@ public class DeploymentApplyEnvironment extends BaseEntity
return new ToStringBuilder(this,ToStringStyle.MULTI_LINE_STYLE)
.append("id", getId())
.append("appId", getAppId())
.append("applyCode", getApplyCode())
.append("applyCode", getAppCode())
.append("name", getName())
.append("serverAddress", getServerAddress())
.append("remark", getRemark())

View File

@ -0,0 +1,241 @@
package com.sf.system.deployment.domain;
import org.apache.commons.lang3.builder.ToStringBuilder;
import org.apache.commons.lang3.builder.ToStringStyle;
import com.sf.common.annotation.Excel;
import com.sf.common.core.domain.BaseEntity;
/**
* H5模块包对象 DEPLOYMENT_MODULE_LIST
*
* @author ztzh
* @date 2024-04-22
*/
public class DeploymentModuleList extends BaseEntity
{
private static final long serialVersionUID = 1L;
/** 主键 */
private Long id;
/** 应用id */
private Long appId;
/** 应用core */
private String appCode;
/** 上传类型 */
private String uploadingType;
/** 模块包名称名称 */
@Excel(name = "模块包名称名称")
private String moduleName;
/** 版本号 */
@Excel(name = "版本号")
private String version;
/** 安装包 */
@Excel(name = "安装包")
private String moduleUrl;
/** 安装包大小 */
@Excel(name = "安装包大小")
private String moduleSize;
/** 系统类型 */
@Excel(name = "系统类型")
private String sysType;
/** 模块类型 */
@Excel(name = "模块类型")
private String moduleType;
/** 上传状态 */
@Excel(name = "上传状态")
private String uploadingStatus;
/** 日志id */
private Long uploadingLogId;
/** 排序 */
private Long orderNum;
/** 逻辑删除,0:未删除,1:删除 */
private Long isDelete;
/** 创建人 */
private String created;
/** 更新人 */
private String modified;
public void setId(Long id)
{
this.id = id;
}
public Long getId()
{
return id;
}
public void setAppId(Long appId)
{
this.appId = appId;
}
public Long getAppId()
{
return appId;
}
public void setAppCode(String appCode)
{
this.appCode = appCode;
}
public String getAppCode()
{
return appCode;
}
public void setUploadingType(String uploadingType)
{
this.uploadingType = uploadingType;
}
public String getUploadingType()
{
return uploadingType;
}
public void setModuleName(String moduleName)
{
this.moduleName = moduleName;
}
public String getModuleName()
{
return moduleName;
}
public void setVersion(String version)
{
this.version = version;
}
public String getVersion()
{
return version;
}
public void setModuleUrl(String moduleUrl)
{
this.moduleUrl = moduleUrl;
}
public String getModuleUrl()
{
return moduleUrl;
}
public void setModuleSize(String moduleSize)
{
this.moduleSize = moduleSize;
}
public String getModuleSize()
{
return moduleSize;
}
public void setSysType(String sysType)
{
this.sysType = sysType;
}
public String getSysType()
{
return sysType;
}
public void setModuleType(String moduleType)
{
this.moduleType = moduleType;
}
public String getModuleType()
{
return moduleType;
}
public void setUploadingStatus(String uploadingStatus)
{
this.uploadingStatus = uploadingStatus;
}
public String getUploadingStatus()
{
return uploadingStatus;
}
public void setUploadingLogId(Long uploadingLogId)
{
this.uploadingLogId = uploadingLogId;
}
public Long getUploadingLogId()
{
return uploadingLogId;
}
public void setOrderNum(Long orderNum)
{
this.orderNum = orderNum;
}
public Long getOrderNum()
{
return orderNum;
}
public void setIsDelete(Long isDelete)
{
this.isDelete = isDelete;
}
public Long getIsDelete()
{
return isDelete;
}
public void setCreated(String created)
{
this.created = created;
}
public String getCreated()
{
return created;
}
public void setModified(String modified)
{
this.modified = modified;
}
public String getModified()
{
return modified;
}
@Override
public String toString() {
return new ToStringBuilder(this,ToStringStyle.MULTI_LINE_STYLE)
.append("id", getId())
.append("appId", getAppId())
.append("appCore", getAppCode())
.append("uploadingType", getUploadingType())
.append("moduleName", getModuleName())
.append("version", getVersion())
.append("moduleUrl", getModuleUrl())
.append("moduleSize", getModuleSize())
.append("sysType", getSysType())
.append("moduleType", getModuleType())
.append("uploadingStatus", getUploadingStatus())
.append("uploadingLogId", getUploadingLogId())
.append("orderNum", getOrderNum())
.append("isDelete", getIsDelete())
.append("created", getCreated())
.append("modified", getModified())
.append("createTime", getCreateTime())
.append("updateTime", getUpdateTime())
.toString();
}
}

Some files were not shown because too many files have changed in this diff Show More